Bu biraz geniş ama bence Gerçek Soruyu anlıyorum ve buna göre cevap vereceğim. Sadece tablo vs dizin biriktirme hakkında konuşacağız. Orada tablo ve dizin makaralar arasında bir seçim olarak görmek oldukça doğru olduğunu düşünmüyorum. Bildiğiniz gibi, tek bir alt ağaçta bir dizin biriktirme, bir tablo biriktirme veya hem bir dizin biriktirme hem de bir tablo biriktirme elde etmek mümkündür. Aşağıdaki koşullarda bir dizin biriktirme aldığınızı söylemek genellikle doğru olduğuna inanıyorum:
- Sorgu iyileştiricinin bir birleştirmeyi bir uygulamaya dönüştürmek için bir nedeni var
- Sorgu iyileştirici, gerçekte uygulamaya dönüştürmeyi gerçekleştirir
- Sorgu iyileştirici, bir dizin biriktirme eklemek için kuralı kullanır (en azından dizin biriktirmenin kullanımı güvenli olmalıdır)
- İndeks makaralı plan seçilir
Bunların çoğunu basit demolarla görebilirsiniz. Bir çift yığın oluşturarak başlayın:
DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_901;
CREATE TABLE dbo.X_10000_VARCHAR_901 (ID VARCHAR(901) NOT NULL);
INSERT INTO dbo.X_10000_VARCHAR_901 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_800;
CREATE TABLE dbo.X_10000_VARCHAR_800 (ID VARCHAR(800) NOT NULL);
INSERT INTO dbo.X_10000_VARCHAR_800 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
İlk sorgu için aranacak bir şey yok:
SELECT *
FROM dbo.X_10000_VARCHAR_901 a
CROSS JOIN dbo.X_10000_VARCHAR_901 b
OPTION (MAXDOP 1);
Dolayısıyla, optimizatörün birleştirmeyi bir uygulamaya dönüştürmesi için hiçbir neden yoktur. Maliyet nedeniyle bir masa makarası ile sonuçlanırsınız. Bu sorgu ilk testi başarısız olur.
Bir sonraki sorgu için, optimize edicinin bir uygulamayı düşünmek için bir nedeni olmasını beklemek adil olacaktır:
SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID = b.ID
OPTION (LOOP JOIN, MAXDOP 1);
Ancak bunun amacı yoktur:
Bu sorgu ikinci sınamada başarısız olur. Tam bir açıklama burada . En alakalı bölümden alıntı:
Optimize edici, bir uygulamayı etkinleştirmek için anında bir dizin oluşturmayı düşünmez; daha ziyade olaylar dizisi genellikle tersidir: iyi bir dizin olduğu için uygulanacak dönüşüm.
Optimize edicinin bir uygulamayı düşünmesini teşvik etmek için sorguyu yeniden yazabilirim:
SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID >= b.ID AND a.ID <= b.ID
OPTION (MAXDOP 1);
Ancak hala dizin biriktirme yok:
Bu sorgu üçüncü sınamada başarısız olur. SQL Server 2014'te, 900 baytlık bir dizin anahtarı uzunluk sınırı vardı. Bu, SQL Server 2016'da genişletildi, ancak yalnızca kümelenmemiş dizinler için. Bir biriktirme dizini kümelenmiş bir dizindir, bu nedenle sınır 900 baytta kalır . Her durumda, dizin biriktirme kuralı, sorgu yürütme sırasında hataya neden olabileceğinden uygulanamaz.
Veri türü uzunluğunu 800'e düşürmek, sonunda bir dizin makarası ile bir plan sağlar:
Endeks biriktirme planının, şaşırtıcı olmayan bir şekilde, biriktirme içermeyen bir plandan çok daha ucuza maliyeti vardır: 89.7603 birim vs 598.832 birim. Belgesiz QUERYRULEOFF BuildSpool
sorgu ipucuyla farkı görebilirsiniz :
Bu tam bir cevap değil, ama umarım aradığınız şeylerden bazılarıdır.