Dizin yürütmeyi daha hızlı yapmıyor ve bazı durumlarda sorguyu yavaşlatıyor. Neden bu kadar?


34

Bir şeyleri hızlandırmak için dizinleri deniyordum, ancak bir katılım durumunda, dizin sorgu yürütme süresini iyileştirmiyor ve bazı durumlarda işleri yavaşlatıyor.

Test tablosu oluşturma ve verilerle doldurma sorgusu:

CREATE TABLE [dbo].[IndexTestTable](
    [id] [int] IDENTITY(1,1) PRIMARY KEY,
    [Name] [nvarchar](20) NULL,
    [val1] [bigint] NULL,
    [val2] [bigint] NULL)

DECLARE @counter INT;
SET @counter = 1;

WHILE @counter < 500000
BEGIN
    INSERT INTO IndexTestTable
      (
        -- id -- this column value is auto-generated
        NAME,
        val1,
        val2
      )
    VALUES
      (
        'Name' + CAST((@counter % 100) AS NVARCHAR),
        RAND() * 10000,
        RAND() * 20000
      );

    SET @counter = @counter + 1;
END

-- Index in question
CREATE NONCLUSTERED INDEX [IndexA] ON [dbo].[IndexTestTable]
(
    [Name] ASC
)
INCLUDE (   [id],
    [val1],
    [val2])

Şimdi iyileştirilmiş olan sorgu 1, (sadece hafif ama iyileştirme tutarlı):

SELECT *
FROM   IndexTestTable I1
       JOIN IndexTestTable I2
            ON  I1.ID = I2.ID
WHERE  I1.Name = 'Name1'

Dizinsiz İstatistikler ve Uygulama Planı (bu durumda tablo varsayılan kümelenmiş dizini kullanır):

(5000 row(s) affected)
Table 'IndexTestTable'. Scan count 2, logical reads 5580, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 109 ms,  elapsed time = 294 ms.

görüntü tanımını buraya girin

Şimdi Dizin etkinken:

(5000 row(s) affected)
Table 'IndexTestTable'. Scan count 2, logical reads 2819, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 94 ms,  elapsed time = 231 ms.

görüntü tanımını buraya girin

Şimdi, dizin nedeniyle yavaşlayan sorgu (yalnızca test için oluşturulduğundan sorgu anlamsızdır):

SELECT I1.Name,
       SUM(I1.val1),
       SUM(I1.val2),
       MIN(I2.Name),
       SUM(I2.val1),
       SUM(I2.val2)
FROM   IndexTestTable I1
       JOIN IndexTestTable I2
            ON  I1.Name = I2.Name
WHERE   
       I2.Name = 'Name1'
GROUP BY
       I1.Name

Kümelenmiş indeks etkinken:

(1 row(s) affected)
Table 'IndexTestTable'. Scan count 4, logical reads 60, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 1, logical reads 155106, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 17207 ms,  elapsed time = 17337 ms.

görüntü tanımını buraya girin

Şimdi Dizin devre dışıyken:

(1 row(s) affected)
Table 'IndexTestTable'. Scan count 5, logical reads 8642, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 2, logical reads 165212, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row(s) affected)

 SQL Server Execution Times:
   CPU time = 17691 ms,  elapsed time = 9073 ms.

görüntü tanımını buraya girin

Sorular:

  1. Dizin, SQL Server tarafından önerilse de, neden önemli bir fark yaratabiliyor?
  2. Çoğu zaman alan İç İçe Döngü birleşimi nedir ve yürütme süresini nasıl geliştirirsiniz?
  3. Yanlış yaptığım ya da kaçırdığım bir şey var mı?
  4. Varsayılan dizinde (yalnızca birincil anahtarda) neden daha az zaman alıyor ve kümelenmemiş dizin mevcutsa, birleştirme tablosundaki her satır için, birleştirilmiş tablo satırının daha hızlı bulunması gerekir, çünkü birleştirme adı sütununda Dizin oluşturuldu. Bu, sorgu yürütme planına yansır ve IndexA etkinken Index Seek maliyeti, IndexA etkinken daha düşüktür, ancak neden hala daha yavaş? Ayrıca yavaşlamaya neden olan Yuvalanmış Döngü sol dış birleştirmesinde neler var?

SQL Server 2012'yi Kullanma

Yanıtlar:


23

Dizin, SQL Server tarafından önerilse de, neden önemli bir fark yaratabiliyor?

Dizin önerileri, sorgu en iyi duruma getiricisi tarafından yapılır. İyi varolan endeksi ile hizmet verilmeyen bir tablodan bir mantıksal seçim rastlarsa o olabilir onun çıkışına bir "kayıp endeksi" öneri eklemek. Bu öneriler fırsatçı; Sorgunun tam bir analizine dayanmazlar ve daha geniş düşünceleri dikkate almazlar. En iyi ihtimalle, daha yararlı endekslemenin mümkün olabileceğinin bir göstergesidir ve yetenekli bir DBA bir bakmalıdır.

Eksik endeks önerileri hakkında söylenecek diğer bir şey, optimizer maliyetleme modeline dayandıkları ve optimize edicinin önerilen endeksin sorgunun tahmini maliyetini ne kadar azaltabileceğini tahmin etmesidir. Buradaki anahtar kelimeler "model" ve "tahminlerdir". Sorgu en iyi duruma getiricisi, donanım yapılandırmanız veya diğer sistem yapılandırma seçenekleriniz hakkında çok az şey biliyor; bu model çoğu zaman çoğu sistemde çoğu insan için makul plan sonuçları üreten sabit numaralara dayanıyor. Kesin maliyet numaraları ile ilgili sorunların yanı sıra, sonuçlar daima tahminidir - ve tahminler yanlış olabilir.

Çoğu zaman alan İç İçe Döngü birleşimi nedir ve yürütme süresini nasıl geliştirirsiniz?

Çapraz birleştirme işleminin performansını artırmak için yapılması gereken çok az şey vardır; iç içe döngüler çapraz birleşme için mümkün olan tek fiziksel uygulamadır. Birleşmenin iç tarafındaki masa makarası, her dış sıra için iç tarafın yeniden taranmasını önlemek için bir optimizasyondur. Bunun yararlı bir performans optimizasyonu olup olmadığı çeşitli faktörlere bağlıdır, ancak testlerimde sorgu onsuz daha iyidir. Yine, bu bir maliyet modeli kullanmanın bir sonucudur - CPU ve bellek sistemim muhtemelen sizinkinden farklı performans özelliklerine sahip. Tablo biriktirmesini önlemek için belirli bir sorgu ipucu yoktur, ancak biriktirme ve biriktirme olmadan yürütme performansını test etmek için kullanabileceğiniz belgesiz bir izleme bayrağı (8690) vardır. Bu gerçek bir üretim sistemi sorunu olsaydı, Makarasız plan, TF 8690 etkinken üretilen plana dayanan bir plan kılavuzu kullanılarak zorlanabilir. Kurulumda teknik olarak desteklenmeyen ve izleme bayraklarının istenmeyen yan etkileri olabileceğinden, üretimde belgesiz iz bayrakları kullanılması önerilmez.

Yanlış yaptığım ya da kaçırdığım bir şey var mı?

Kaçırdığınız asıl şey, kümelenmemiş endeksi kullanan planın optimize edicinin modeline göre daha düşük bir tahmini maliyeti olmasına rağmen, önemli bir yürütme zamanı problemi olmasıdır. Kümelenmiş Dizini kullanarak plandaki dişler arasındaki satırların dağılımına bakarsanız, muhtemelen oldukça iyi bir dağılım göreceksiniz:

Tarama planı

Kümelenmemiş Endeks Aramanın kullanıldığı planda, çalışma tamamen tek bir iş parçacığı tarafından gerçekleştirilir:

Plan ara

Bu, paralel tarama / arama işlemleri ile işin dişler arasında dağıtılmasının bir sonucudur. Paralel taramanın işi dizin aramaya göre daha iyi dağıtacağı her zaman durum böyle değildir - ancak bu durumda yapar. Daha karmaşık planlar arasında, iş başlıkları arasında yeniden dağıtmak için yeniden bölümlendirme borsaları bulunabilir. Bu plan böyle bir borsaya sahip değildir, bu yüzden sıralar bir konuya atandığında, ilgili tüm işler aynı konu üzerinde gerçekleştirilir. Yürütme planındaki diğer operatörler için iş dağıtımına bakarsanız, tüm işlerin indeks araması için gösterilen iş parçacığı tarafından gerçekleştirildiğini göreceksiniz.

İş parçacığı arasındaki satır dağılımını etkileyecek hiçbir sorgu ipucu yoktur, önemli olan, olasılığın farkında olmak ve bir soruna ne zaman neden olacağını belirlemek için yürütme planında yeterince ayrıntı okuyabilmektir.

Varsayılan dizinde (yalnızca birincil anahtarda) neden daha az zaman alıyor ve kümelenmemiş dizin mevcutsa, birleştirme tablosundaki her satır için, birleştirilmiş tablo satırının daha hızlı bulunması gerekir, çünkü birleştirme adı sütununda Dizin oluşturuldu. Bu, sorgu yürütme planına yansır ve IndexA etkinken Index Seek maliyeti, IndexA etkinken daha düşüktür, ancak neden hala daha yavaş? Ayrıca yavaşlamaya neden olan Yuvalanmış Döngü sol dış birleştirmesinde neler var?

Şimdi kümelenmemiş indeks planının beklediğiniz gibi potansiyel olarak daha verimli olduğu açık olmalı; sadece performans meselesini hesaba katan yürütme sırasındaki iş parçacığı arasında işin zayıf dağıtılmasıdır.

Örneği tamamlama ve bahsettiğim bazı şeyleri açıklama amacıyla, daha iyi bir iş dağıtımı elde etmenin bir yolu, paralel yürütmeyi yürütmek için geçici bir tablo kullanmaktır:

SELECT
    val1,
    val2
INTO #Temp
FROM dbo.IndexTestTable AS ITT
WHERE Name = N'Name1';

SELECT 
    N'Name1',
    SUM(T.val1),
    SUM(T.val2),
    MIN(I2.Name),
    SUM(I2.val1),
    SUM(I2.val2)
FROM   #Temp AS T
CROSS JOIN IndexTestTable I2
WHERE
    I2.Name = 'Name1'
OPTION (FORCE ORDER, QUERYTRACEON 8690);

DROP TABLE #Temp;

Bu, daha verimli bir indeks kullanan, bir tablo biriktirme özelliği bulunmayan ve işi dişler arasında iyi bir şekilde dağıtan bir planla sonuçlanır:

Optimal plan

Sistemimde, bu plan Kümelenmiş Dizin Taraması sürümünden önemli ölçüde daha hızlı çalışır.

Paralel sorgu yürütme içindekiler hakkında daha fazla bilgi edinmek istiyorsanız, PASS Summit 2013 oturum kaydını izlemek isteyebilirsiniz .


0

Bu gerçekten endeksin bir sorusu değil, daha kötü bir şekilde yazılmış bir sorundur. Yalnızca 100 benzersiz ad değeriniz var, bu ad başına 5000 adında benzersiz bir sayı bırakıyor.

Yani tablo 1'deki her satır için tablo 2'den 5000'e katılıyorsunuz. 25020004 satır diyebilirsiniz.

Bunu deneyin, bunun listelediğiniz dizinin sadece 1 dizin olduğunu unutmayın.

    DECLARE @Distincts INT
    SET @Distincts = (SELECT  TOP 1 COUNT(*) FROM IndexTestTable I1 WHERE I1.Name = 'Name1' GROUP BY I1.Name)
    SELECT I1.Name
    , @Distincts
    , SUM(I1.val1) * @Distincts
    , SUM(I1.val2) * @Distincts
    , MIN(I2.Name)
    , SUM(I2.val1)
    , SUM(I2.val2)
    FROM   IndexTestTable I1
    LEFT OUTER JOIN

    (
        SELECT I2.Name
        , SUM(I2.val1) val1
        , SUM(I2.val2) val2
        FROM IndexTestTable I2
        GROUP BY I2.Name
    ) I2 ON  I1.Name = I2.Name
    WHERE I1.Name = 'Name1'
    GROUP BY  I1.Name

Ve zaman:

    SQL Server parse and compile time: 
       CPU time = 0 ms, elapsed time = 8 ms.
    Table 'IndexTestTable'. Scan count 1, logical reads 31, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

     SQL Server Execution Times:
       CPU time = 0 ms,  elapsed time = 1 ms.

    (1 row(s) affected)
    Table 'IndexTestTable'. Scan count 2, logical reads 62, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

     SQL Server Execution Times:
       CPU time = 16 ms,  elapsed time = 10 ms.

görüntü tanımını buraya girin

Kötü biçimlendirilmiş sorgular için SQL dizinlerini suçlayamazsınız


1
Cevabınız için teşekkürler ve evet sorgusu geliştirilebilir, ancak sorumun mantığı, varsayılan dizinde (yalnızca birincil anahtarda) neden daha az zaman alıyor ve kümelenmemiş dizin mevcutken katılım tablosunda, birleştirilen tablo sırasının daha hızlı bulunması gerekir, bu da sorgu yürütme planında yansıtılır ve IndexA etkinken Index Seek maliyeti daha düşüktür, ancak neden hala daha yavaş? Ayrıca yavaşlamaya neden olan Yuvalanmış Döngü sol dış birleştirmesinde neler var? Soruyu daha net hale getirmek için bu yorumu eklemek için soruyu düzenledim.
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.