Neden sys.query_store_plan ile eleme çalışmalarına katılmıyorsunuz?


10

Sorgu Deposu'nda karşılaşılan bir performans sorununun basitleştirilmesidir:

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;

plan_idSütun birincil anahtar olarak belgelenmiştir sys.query_store_plan, ancak yürütme planı kullanmaz ortadan kaldırılması katılmak beklenir gibi:

  1. DMV'den hiçbir özellik yansıtılmıyor.
  2. DMV birincil anahtarı plan_id, geçici tablodaki satırları çoğaltamaz
  3. A LEFT JOINkullanılır, böylece hiçbir satır Tortadan kaldırılamaz.

Yürütme planı

plan grafiği

Bu neden böyle ve katılmaya elemeyi elde etmek için ne yapılabilir?

Yanıtlar:


16

Dokümantasyon biraz yanıltıcı. DMV, gerçekleşmemiş bir görünümdür ve bu şekilde birincil bir anahtarı yoktur. Temel tanımlamalar biraz karmaşıktır, ancak basitleştirilmiş bir tanımı sys.query_store_plan:

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;

Dahası, sys.plan_persist_plan_mergedaynı zamanda bir görünümdür, ancak tanımını görmek için Adanmış Yönetici Bağlantısı üzerinden bağlanması gerekir. Tekrar, basitleştirilmiş:

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;

Üzerindeki dizinler sys.plan_persist_plan:

╔════════════════════════╦════════════════════════ ══════════════╦═════════════╗
║ index_name ║ index_description ║ index_keys ║
╠════════════════════════╬════════════════════════ ══════════════╬═════════════╣
║ plan_persist_plan_cidx ║ PRIMARY located plan_id'de bulunan kümelenmiş, benzersiz ║
║ plan_persist_plan_idx1 ║ PRIMARY üzerinde kümelenmemiş ║ query_id (-) ║
╚════════════════════════╩════════════════════════ ══════════════╩═════════════╝

Yani plan_idbenzersiz olmakla sınırlıdır sys.plan_persist_plan.

Şimdi, sys.plan_persist_plan_in_memoryyalnızca dahili bellek yapılarında tutulan verilerin tablo şeklinde bir görünümünü sunan, akış değerli tablo değerli bir işlevdir. Bu nedenle, benzersiz bir kısıtlaması yoktur.

Yürürlükte olan sorgu bu nedenle:

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;

... birleştirme ortadan kaldırması üretmeyen:

resim açıklamasını buraya girin

Sorunun özüne doğru gidersek, sorun iç sorgudur:

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;

... açıkça sol birleşim satırların @t2çoğaltılmasına neden olabilir, çünkü @t3tek başına herhangi bir kısıtlama yoktur plan_id. Bu nedenle, birleştirme ortadan kaldırılamaz:

resim açıklamasını buraya girin

Bu sorunu çözmek için, optimize ediciye yinelenen herhangi bir plan_iddeğer gerekmediğini açıkça söyleyebiliriz :

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;

@t3Şimdi dış birleşim ortadan kaldırılabilir:

resim açıklamasını buraya girin

Bunu gerçek sorguya uygulamak:

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

Aynı şekilde, GROUP BY T.plan_idyerine de ekleyebiliriz DISTINCT. Her neyse, optimize edici artık plan_idözellik hakkında iç içe görünümler boyunca doğru bir şekilde gerekçelendirebilir ve her iki dış birleşimi istendiği gibi ortadan kaldırabilir:

resim açıklamasını buraya girin

plan_idGeçici tabloda benzersiz hale getirmenin , yanlış sonuçları engellemeyeceği için birleştirme eliminasyonu elde etmek için yeterli olmayacağını unutmayın. plan_idOptimize edicinin sihrini burada çalıştırabilmesi için nihai sonuçtaki yinelenen değerleri açıkça reddetmeliyiz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.