Mengapa tidak bergabung dengan eliminasi bekerja dengan sys.query_store_plan?


10

Berikut ini adalah penyederhanaan masalah kinerja yang dihadapi dengan Query Store:

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;

The plan_idkolom didokumentasikan sebagai kunci utama sys.query_store_plan, tapi rencana eksekusi tidak menggunakan bergabung eliminasi seperti yang diharapkan:

  1. Tidak ada atribut yang diproyeksikan dari DMV.
  2. Kunci utama DMV plan_idtidak dapat menduplikasi baris dari tabel sementara
  3. A LEFT JOINdigunakan, jadi tidak ada baris dari Tdapat dihilangkan.

Rencana eksekusi

grafik rencana

Mengapa ini, dan apa yang bisa dilakukan untuk mendapatkan penghapusan bergabung di sini?

Jawaban:


16

Dokumentasinya sedikit menyesatkan. DMV adalah pandangan yang tidak terwujud, dan tidak memiliki kunci primer seperti itu. Definisi yang mendasarinya sedikit rumit tetapi definisi yang disederhanakan sys.query_store_planadalah:

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;

Lebih lanjut, sys.plan_persist_plan_mergedini juga merupakan pandangan, meskipun seseorang harus terhubung melalui Koneksi Administrator Khusus untuk melihat definisinya. Sekali lagi, disederhanakan:

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;

Indeks yang aktif sys.plan_persist_planadalah:

╔════════════════════════╦════════════════════════ ══════════════╦═════════════╗
║ index_name ║ index_description ║ index_keys ║
╠════════════════════════╬════════════════════════ ══════════════╬═════════════╣
║ plan_persist_plan_cidx ║ berkerumun, unik terletak di PRIMARY ║ plan_id ║
║ plan_persist_plan_idx1 ║ nonclustered terletak di PRIMARY ║ query_id (-) ║
╚════════════════════════╩════════════════════════ ══════════════╩═════════════╝

Jadi plan_iddibatasi untuk menjadi unik sys.plan_persist_plan.

Sekarang, sys.plan_persist_plan_in_memoryadalah fungsi streaming yang dihargai tabel, menyajikan tampilan tabular data yang hanya disimpan dalam struktur memori internal. Karena itu, tidak memiliki kendala unik.

Karena itu, kueri yang dijalankan setara dengan:

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;

... yang tidak menghasilkan eliminasi gabungan:

masukkan deskripsi gambar di sini

Langsung ke inti masalah, masalahnya adalah kueri batin:

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;

... jelas gabung kiri mungkin menghasilkan baris dari @t2duplikasi karena @t3tidak memiliki kendala keunikan plan_id. Karenanya, join tidak dapat dihilangkan:

masukkan deskripsi gambar di sini

Untuk mengatasinya, kami dapat secara eksplisit memberi tahu pengoptimal bahwa kami tidak memerlukan plan_idnilai duplikat :

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;

Gabung luar ke @t3sekarang dapat dihilangkan:

masukkan deskripsi gambar di sini

Menerapkannya ke permintaan sebenarnya:

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

Sama, kita bisa menambahkan GROUP BY T.plan_idbukan DISTINCT. Pokoknya, pengoptimal sekarang dapat dengan benar alasan tentang plan_idatribut sepanjang jalan melalui tampilan bersarang, dan menghilangkan kedua gabungan luar yang diinginkan:

masukkan deskripsi gambar di sini

Perhatikan bahwa membuat plan_idunik di tabel sementara tidak akan cukup untuk mendapatkan eliminasi gabungan, karena itu tidak akan menghalangi hasil yang salah. Kami harus secara eksplisit menolak plan_idnilai duplikat dari hasil akhir untuk memungkinkan pengoptimal bekerja dengan baik di sini.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.