Bu sorgu neden bir dizin biriktirme kullanmıyor?


23

Optimize Edici'nin davranışını daha iyi anlamak ve indeks biriktiricileri etrafındaki limitleri anlamak için bu soruyu soruyorum. 1 - 10000 arasında bir tamsayıyı bir yığına koyduğumu varsayalım:

CREATE TABLE X_10000 (ID INT NOT NULL);
truncate table X_10000;

INSERT INTO X_10000 WITH (TABLOCK)
SELECT TOP 10000 ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

Ve iç içe geçmiş bir döngü ile birleşmeye zorlayın MAXDOP 1:

SELECT *
FROM X_10000 a
INNER JOIN X_10000 b ON a.ID = b.ID
OPTION (LOOP JOIN, MAXDOP 1);

Bu, SQL Server'a yönelik yapılması gereken oldukça düşmanca bir eylemdir. İç içe geçmiş döngü birleşimleri, her iki tablonun da ilgili dizinleri olmadığında, genellikle iyi bir seçim değildir. İşte plan:

hatalı sorgu

Sorgu makinemde 1300, masa makarasından 100000000 satır alındı. Ancak, sorgunun neden yavaş olması gerektiğini anlamıyorum. Sorgu en iyi duruma getiricisi, dizin makaraları aracılığıyla anında dizin oluşturma yeteneğine sahiptir . Bu sorgu bir dizin biriktirme için mükemmel bir aday olacak gibi görünüyor.

Aşağıdaki sorgu, birincisiyle aynı sonuçları döndürür, bir dizin biriktiricisine sahiptir ve bir saniyeden daha kısa bir sürede biter:

SELECT *
FROM X_10000 a
CROSS APPLY (SELECT TOP (9223372036854775807) b.ID FROM X_10000 b WHERE a.ID = b.ID) ca
OPTION (LOOP JOIN, MAXDOP 1);

geçici çözüm 1

Bu sorguda ayrıca bir dizin biriktirme var ve bir saniyeden daha kısa sürede bitiyor:

SELECT *
FROM X_10000 a
INNER JOIN X_10000 b ON a.ID >= b.ID AND a.ID <= b.ID
OPTION (LOOP JOIN, MAXDOP 1);

geçici çözüm 2

Orijinal sorgunda neden bir dizin biriktirme var? Dizin biriktirecek herhangi bir belgelenmiş veya belgelenmemiş ipucu veya iz bayrağı seti var mı? İlgili soruyu buldum , ancak sorumu tam olarak yanıtlamıyor ve gizemli iz bayrağının bu sorgu için çalışmasını sağlayamıyorum.

Yanıtlar:


20

Bildiğiniz gibi, optimizer'ın araması kapsamlı değil. Bağlamsal anlamda anlamlı olan ve gerçek sorulara temettü ödeyen şeyleri dener. İki tek sütunlu, katlanmamış yığın tabloları arasında bir döngü birleşmesini zorlamak böyle bir senaryo değildir. Dedi ki, işte bazı detaylar:

SQL Server dönüştürmeyi sever, katılımlar için daha fazla püf noktası olduğu için katılımlara erken uygulanır. Daha sonra, birleşimi tekrar başvuruya dönüştürmeyi keşfedebilir. İkisi arasındaki fark varlık ilişkili parametreleri (dış referanslar). İç tarafta uygun bir indeks bulunduğunda, uygulamalar anlamlıdır. Örneğinizde dizin yok, bu nedenle en iyileştirici bir uygulamaya yapılan çeviriyi keşfetmeye ikna olmaz.

Basit (başvuru dışı) bir birleşim, dış referanslar yerine birleştirme operatöründe birleştirme öngörüsüne sahiptir. Uygulanmayanlar için makara optimizasyonu, tipik olarak tembel bir masa makarasıdır, çünkü iç tarafta sadece birleşimde herhangi bir belirti yoktur.

Doktoru, bir başvuruyu etkinleştirmek için anında bir endeks oluşturmayı düşünmez; bunun yerine olayların sırası genellikle tersidir: iyi bir dizin olduğundan uygulama için dönüşüm.

Bazen APPLYsorgunuzdaki sözdizimini kullanarak bir katılım yerine bir başvuruyu teşvik edebilirsiniz . Belgelenmemiş iz bayrağı 9114, optimize edicinin bir birleştirme cephesine mantıksal bir başvuruyu tercüme etmesini engelleyerek bu konuda yardımcı olabilir. Örneğin:

SELECT * 
FROM dbo.X_1000 AS a
CROSS APPLY (SELECT * FROM dbo.X_1000 AS b WHERE b.ID = a.ID) AS b
OPTION (QUERYTRACEON 9114);

Biriktirme planı

Bir referans makarası, uygulama için tercih edilir, çünkü dış referans, seçimin birleşimin iç tarafına uygulandığı anlamına gelir. Bunu sık sık göreceksiniz SelToIndexOnTheFlyama başka yollar var. Makaleme bakın Eager Index Spool ve En İyileştirici .

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.