Tại sao không tham gia loại bỏ hoạt động với sys.query_store_plan?


10

Sau đây là đơn giản hóa vấn đề về hiệu năng gặp phải với Cửa hàng truy vấn:

CREATE TABLE #tears
(
    plan_id bigint NOT NULL
);

INSERT #tears (plan_id) 
VALUES (1);

SELECT
    T.plan_id
FROM #tears AS T
LEFT JOIN sys.query_store_plan AS QSP
    ON QSP.plan_id = T.plan_id;

Các plan_idcột được ghi nhận như là khóa chính của sys.query_store_plan, nhưng kế hoạch thực hiện không sử dụng tham gia loại trừ như được mong đợi:

  1. Không có thuộc tính nào được chiếu từ DMV.
  2. Khóa chính DMV plan_idkhông thể sao chép các hàng từ bảng tạm thời
  3. A LEFT JOINđược sử dụng, vì vậy không có hàng nào Tcó thể được loại bỏ.

Kế hoạch thực hiện

kế hoạch đồ họa

Tại sao điều này, và những gì có thể được thực hiện để có được loại bỏ tham gia ở đây?

Câu trả lời:


16

Các tài liệu là một chút sai lệch. DMV là chế độ xem không cụ thể hóa và không có khóa chính như vậy. Các định nghĩa cơ bản là một chút phức tạp nhưng một định nghĩa đơn giản sys.query_store_planlà:

CREATE VIEW sys.query_store_plan AS
SELECT
    PPM.plan_id
    -- various other attributes
FROM sys.plan_persist_plan_merged AS PPM
LEFT JOIN sys.syspalvalues AS P
    ON P.class = 'PFT' 
    AND P.[value] = plan_forcing_type;

Hơn nữa, sys.plan_persist_plan_mergedcũng là một khung nhìn, mặc dù người ta cần kết nối thông qua Kết nối quản trị viên chuyên dụng để xem định nghĩa của nó. Một lần nữa, đơn giản hóa:

CREATE VIEW sys.plan_persist_plan_merged AS   
SELECT     
    P.plan_id as plan_id,    
    -- various other attributes
FROM sys.plan_persist_plan P 
    -- NOTE - in order to prevent potential deadlock
    -- between QDS_STATEMENT_STABILITY LOCK and index locks   
    WITH (NOLOCK) 
LEFT JOIN sys.plan_persist_plan_in_memory PM
    ON P.plan_id = PM.plan_id;

Các chỉ số trên sys.plan_persist_planlà:

╔════════════════════════╦════════════════════════ ══════════════╦═════════════╗
║ index_name ║ index_description ║ index_keys
╠════════════════════════╬════════════════════════ ══════════════╬═════════════╣
║ plan_persist_plan_cidx ║ cụm, duy nhất nằm trên PRIMARY plan_id
║ plan_persist_plan_idx1 không được đặt trên PRIMARY ║ query_id (-)
╚════════════════════════╩════════════════════════ ══════════════╩═════════════╝

Vì vậy, plan_idbị hạn chế là duy nhất trên sys.plan_persist_plan.

Bây giờ, sys.plan_persist_plan_in_memorylà một hàm có giá trị bảng phát trực tuyến, hiển thị dạng xem bảng của dữ liệu chỉ được giữ trong các cấu trúc bộ nhớ trong. Như vậy, nó không có bất kỳ ràng buộc duy nhất.

Do đó, truy vấn đang được thực hiện tương đương với:

DECLARE @t1 table (plan_id integer NOT NULL);
DECLARE @t2 table (plan_id integer NOT NULL UNIQUE CLUSTERED);
DECLARE @t3 table (plan_id integer NULL);

SELECT 
    T1.plan_id
FROM @t1 AS T1 
LEFT JOIN
(
    SELECT 
        T2.plan_id
    FROM @t2 AS T2
    LEFT JOIN @t3 AS T3 
        ON T3.plan_id = T2.plan_id
) AS Q1
    ON Q1.plan_id = T1.plan_id;

... mà không tạo ra sự loại bỏ tham gia:

nhập mô tả hình ảnh ở đây

Đi thẳng vào cốt lõi của vấn đề, vấn đề là truy vấn bên trong:

DECLARE @t2 table (plan_id integer NOT NULL UNIQUE CLUSTERED);
DECLARE @t3 table (plan_id integer NULL);

SELECT 
    T2.plan_id
FROM @t2 AS T2
LEFT JOIN @t3 AS T3 
    ON T3.plan_id = T2.plan_id;

... rõ ràng việc nối bên trái có thể khiến các hàng không @t2bị trùng lặp vì @t3không có ràng buộc duy nhất nào plan_id. Do đó, việc tham gia không thể được loại bỏ:

nhập mô tả hình ảnh ở đây

Để khắc phục điều này, chúng tôi có thể nói rõ ràng với trình tối ưu hóa rằng chúng tôi không yêu cầu bất kỳ plan_idgiá trị trùng lặp nào :

DECLARE @t2 table (plan_id integer NOT NULL UNIQUE CLUSTERED);
DECLARE @t3 table (plan_id integer NULL);

SELECT DISTINCT
    T2.plan_id
FROM @t2 AS T2
LEFT JOIN @t3 AS T3 
    ON T3.plan_id = T2.plan_id;

Tham gia bên ngoài để @t3bây giờ có thể được loại bỏ:

nhập mô tả hình ảnh ở đây

Áp dụng điều đó cho truy vấn thực sự:

SELECT DISTINCT
    T.plan_id
FROM #tears AS T
LEFT JOIN sys.query_store_plan AS QSP
    ON QSP.plan_id = T.plan_id;

Tương tự, chúng ta có thể thêm GROUP BY T.plan_idthay vì DISTINCT. Dù sao, trình tối ưu hóa giờ đây có thể lý giải chính xác về plan_idthuộc tính cho đến hết các khung nhìn lồng nhau và loại bỏ cả hai phép nối ngoài như mong muốn:

nhập mô tả hình ảnh ở đây

Lưu ý rằng làm cho plan_idduy nhất trong bảng tạm thời sẽ không đủ để có được loại bỏ tham gia, vì nó sẽ không loại trừ kết quả không chính xác. Chúng ta phải từ chối một cách rõ ràng plan_idcác giá trị trùng lặp từ kết quả cuối cùng để cho phép trình tối ưu hóa thực hiện phép thuật của nó ở đây.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.