Temp değişkeni arama ve yer imi aramayı kullanırken tablo değişkeni neden bir dizin taramasını zorlar?


18

Neden bir tablo değişkeni kullanarak bir dizin arama ve sonra yer işareti arama karşı bir yer imi arama kullanarak optimize edici önleyici olduğunu anlamaya çalışıyorum.

Masayı doldurmak:

CREATE TABLE dbo.Test 
(
    RowKey INT NOT NULL PRIMARY KEY, 
    SecondColumn CHAR(1) NOT NULL DEFAULT 'x',
    ForeignKey INT NOT NULL 
) 

INSERT dbo.Test 
(
    RowKey, 
    ForeignKey
) 
SELECT TOP 1000000 
    ROW_NUMBER() OVER (ORDER BY (SELECT 0)),
    ABS(CHECKSUM(NEWID()) % 10)     
FROM sys.all_objects s1
CROSS JOIN sys.all_objects s2 

CREATE INDEX ix_Test_1 ON dbo.Test (ForeignKey) 

Bir tablo değişkenini tek bir kayıtla doldurun ve yabancı anahtar sütununda arama yaparak birincil anahtarı ve ikinci sütunu aramaya çalışın:

DECLARE @Keys TABLE (RowKey INT NOT NULL) 

INSERT @Keys (RowKey) VALUES (10)

SELECT 
    t.RowKey,
    t.SecondColumn
FROM
    dbo.Test t 
INNER JOIN 
    @Keys k
ON
    t.ForeignKey = k.RowKey

Uygulama planı aşağıdadır:

resim açıklamasını buraya girin

Şimdi aynı sorgu yerine geçici tablo kullanarak:

CREATE TABLE #Keys (RowKey INT NOT NULL) 

INSERT #Keys (RowKey) VALUES (10) 

SELECT 
    t.RowKey,
    t.SecondColumn
FROM
    dbo.Test t 
INNER JOIN 
    #Keys k
ON
    t.ForeignKey = k.RowKey

Bu sorgu planı bir arama ve yer işareti araması kullanır:

resim açıklamasını buraya girin

Optimizer neden yer değişkeni temp tablosuyla arama yapıyor, ancak table değişkeni ile değil?

Tablo değişkeni bu örnekte, saklı yordamda kullanıcı tanımlı bir tablo türünden gelen verileri temsil etmek için kullanılır.

Yabancı anahtar değeri yüzbinlerce kez gerçekleştiğinde endeks arayışının uygun olmayabileceğini biliyorum. Bu durumda, tarama muhtemelen daha iyi bir seçim olacaktır. Oluşturduğum senaryo için, değeri 10 olan bir satır yoktu. Davranışın ilginç olduğunu ve bunun bir nedeni olup olmadığını bilmek istiyorum.

SQL Keman

Ekleme OPTION (RECOMPILE)davranışı değiştirmedi. UDDT'nin birincil anahtarı vardır.

@@VERSION Server 2008 R2 (SP2) - 10.50.4042.0 (X64) (Derleme 7601: Service Pack 1) nedir (Hipervizör)

Yanıtlar:


15

Davranışın nedeni, SQL Server'ın RowKey ile önde gelen sütun olarak bir dizin olmadığından (#temp tablosundaki istatistiklerden çıkarabileceği için, kaç satırın ForeignKey ile eşleşeceğini belirleyememesidir, ancak bunlar tablo değişkenleri / UDTT'ler için mevcut), bu nedenle 100.000 satırlık bir tahmin yapar, bu da arama ile arama + aramasından daha iyi işlenir. SQL Server yalnızca bir satır olduğunu fark ettiğinde, artık çok geç.

UDTT'nizi farklı şekilde yapılandırabilirsiniz; SQL Server'ın daha modern sürümlerinde tablo değişkenleri üzerinde ikincil dizinler oluşturabilirsiniz, ancak bu sözdizimi 2008 R2'de kullanılamaz.

BTW, iç içe geçmiş döngülerin katılmasını ima ederek bitmap / probdan kaçınmaya çalışırsanız arama davranışını (en azından sınırlı denemelerde) alabilirsiniz:

DECLARE @Keys TABLE (RowKey INT PRIMARY KEY); -- can't hurt

INSERT @Keys (RowKey) VALUES (10);

SELECT 
     t.RowKey
    ,t.SecondColumn
FROM
    dbo.Test t 
INNER JOIN 
    @Keys k
ON
    t.ForeignKey = k.RowKey
    OPTION (LOOP JOIN);

Ben Paul Beyaz gelen bu hileyi öğrendiği birkaç yıl önce. Tabii ki, üretim koduna herhangi bir birleştirme ipucu koymak konusunda dikkatli olmalısınız - bu, insanlar temeldeki nesnelerde değişiklik yaparsa ve bu özel birleştirme türü artık mümkün değilse veya artık en uygun değilse başarısız olabilir.

Daha karmaşık sorgular için ve SQL Server 2012 veya sonraki bir sürüme geçtiğinizde, izleme bayrağı 2453 yardımcı olabilir. Bu bayrak bu basit birleşmeye yardımcı olmadı. Ve aynı feragatnameler geçerli olacaktır - bu, bir ton belge ve titiz regresyon testi prosedürü olmadan genellikle yapmamanız gereken alternatif bir şeydir.

Ayrıca, Service Pack 1 uzun süredir desteklenmemektedir, Service Pack 3 + MS15-058'i kullanmanız gerekir .


3

Tablo değişkenleri ve geçici tablolar çeşitli şekillerde farklı şekilde ele alınır. Burada, farklı oldukları yere dair birçok özelliğin olduğu harika bir cevap var .

Özellikle sizin durumunuzda, geçici değişkenlerin ek istatistikler oluşturulmuş ve paralel planlar olabileceği tahmin edilirken, tablo değişkenleri daha sınırlı istatistiklere (sütun seviyesi istatistikleri yok) ve paralel planlara sahip olmamanız suçludur.

Saklı yordam süresince tablo değişkenini geçici bir tabloya boşaltmak çok daha iyi olabilir.

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.