Yanıtlar:
Çok deyimli tablo değerli bir işlevin (msTVF) sonuçları asla ifadeler (veya bağlantılar) arasında önbelleğe veya yeniden kullanılmaz, ancak bir msTVF sonucunun aynı ifade içinde yeniden kullanılabileceği birkaç yol vardır . Bu ölçüde, bir msTVF her çağrıldığında mutlaka doldurulmaz.
Bu (bilerek etkin değil) msTVF, her satırda bir zaman damgası olan belirli bir tam sayı aralığı döndürür:
IF OBJECT_ID(N'dbo.IntegerRange', 'TF') IS NOT NULL
DROP FUNCTION dbo.IntegerRange;
GO
CREATE FUNCTION dbo.IntegerRange (@From integer, @To integer)
RETURNS @T table
(
n integer PRIMARY KEY,
ts datetime DEFAULT CURRENT_TIMESTAMP
)
WITH SCHEMABINDING
AS
BEGIN
WHILE @From <= @To
BEGIN
INSERT @T (n)
VALUES (@From);
SET @From = @From + 1;
END;
RETURN;
END;
İşlev çağrısının tüm parametreleri sabitse (veya çalışma zamanı sabitleri), yürütme planı tablo değişkeni sonucunu bir kez doldurur. Planın geri kalanı tablo değişkenine birçok kez erişebilir. Tablo değişkeninin statik yapısı yürütme planından tanınabilir. Örneğin:
SELECT
IR.n,
IR.ts
FROM dbo.IntegerRange(1, 5) AS IR
ORDER BY
IR.n;
Şuna benzer bir sonuç döndürür:
Yürütme planı:
Sıralama operatörü ilk önce tablo değişkenini dolduran Tablo Değerli Fonksiyon operatörünü çağırır (bu operatörün satır döndürmediğini unutmayın). Ardından, Sıra tablo değişkeninin içeriğini döndüren ikinci girişini çağırır (bu durumda Kümelenmiş Dizin Taraması kullanarak).
Planın 'statik' bir tablo değişkeni sonucu kullandığı hediye, bir Dizinin altındaki Tablo Değerli İşlev işlecidir - tablo değişkeninin, planın geri kalanının başlayabilmesi için bir kez önce doldurulması gerekir.
Bir kereden fazla erişilen tablo değişkeni sonucunu göstermek için, 1'den 5'e kadar sıralanan satırlara sahip ikinci bir tablo kullanacağız:
IF OBJECT_ID(N'dbo.T', 'U') IS NOT NULL
DROP TABLE dbo.T;
CREATE TABLE dbo.T (i integer NOT NULL);
INSERT dbo.T (i)
VALUES (1), (2), (3), (4), (5);
Ve bu tabloyu fonksiyonumuza ekleyen yeni bir sorgu (bu eşit olarak bir yazılabilir APPLY
):
SELECT T.i,
IR.n,
IR.ts
FROM dbo.T AS T
JOIN dbo.IntegerRange(1, 5) AS IR
ON IR.n = T.i;
Sonuç:
Yürütme planı:
Daha önce olduğu gibi, Dizi ilk önce msTVF sonucundaki değişken değişkenini doldurur. Daha sonra, iç içe döngüler tablodaki her satıra katılmak için kullanılırT
msTVF sonucundan bir satıra eklemek için kullanılır. İşlev tanımı, tablo değişkenine yardımcı bir dizin içerdiğinden, bir dizin araması kullanılabilir.
Kilit nokta, msTVF'nin parametreleri sabit olduğunda (değişkenler ve parametreler dahil) veya yürütme motoru tarafından ifade için çalışma zamanı sabitleri olarak değerlendirildiğinde, plan, msTVF tablo değişkeni sonucu için iki ayrı işleci içerecektir: tablo; sonuçlara erişmek, muhtemelen tabloya birden çok kez erişmek ve işlev tanımında beyan edilen indeksleri kullanmak için bir başka sonuç.
İlişkili parametreler (dış referanslar) veya sabit olmayan fonksiyon parametreleri kullanıldığında farkları vurgulamak için, tablonun içeriğini değiştireceğiz, T
böylece fonksiyonun yapacak daha çok işi olacaktır:
TRUNCATE TABLE dbo.T;
INSERT dbo.T (i)
VALUES (50001), (50002), (50003), (50004), (50005);
Aşağıdaki değiştirilmiş sorgu şimdi T
işlev parametrelerinden birinde tabloya bir dış başvuru kullanıyor :
SELECT T.i,
IR.n,
IR.ts
FROM dbo.T AS T
CROSS APPLY dbo.IntegerRange(1, T.i) AS IR
WHERE IR.n = T.i;
Bu sorgu, şöyle sonuç döndürmek için yaklaşık 8 saniye sürer :
Sütun içindeki satırlar arasındaki zaman farkına dikkat edin ts
. WHERE
Maddesi bir makul büyüklükte bir çıkış için nihai sonucu sınırlar, verimsiz fonksiyonu hala 50.000 tek sıra (dekorele değerine bağlı olarak tablo değişken doldurmak için bir süre alır i
tablodan T
).
Yürütme planı:
Sıra operatörünün eksikliğine dikkat edin. Şimdi, tablo değişkenini dolduran ve iç içe geçmiş döngüler birleşiminin her yinelemesinde satırlarını döndüren tek bir Tablo Değerli İşlev işleci var .
Açık olması: Tablo T'deki sadece 5 satır ile Tablo Değerli İşlev işleci 5 kez çalışır. İlk yinelemede 50.001 satır, ikincisinde 50.002 satır vb. Oluşturur. Tablo değişkeni yinelemeler arasında 'atılır' (kesilir), bu nedenle beş çağrının her biri tam bir popülasyondur. Bu yüzden çok yavaştır ve her satırın sonuçta görünmesi yaklaşık aynı zaman alır.
Yan notlar:
Doğal olarak, yukarıdaki senaryo, msTVF'nin her bir yinelemede birçok satır doldurduğunda performansın ne kadar düşük olabileceğini göstermeye kasıtlı olarak düzenlenmektedir.
Bir mantıklı Yukarıdaki kod uygulaması kuracak hem üzere msTVF parametreleri i
ve gereksiz kaldırmak WHERE
maddesini. Tablo değişkeni hala her yinelemede kesilir ve yeniden doldurulur, ancak her seferinde yalnızca bir satır olur.
Ayrıca minimum ve maksimum i
değerleri alabilir T
ve önceki adımda değişkenlerde saklayabiliriz. İlişkili parametreler yerine değişkenlerle fonksiyon çağırmak, 'statik' tablo değişken modelinin daha önce belirtildiği gibi kullanılmasını sağlar.
Sıradaki soruyu bir kez daha ele almak için, Sıra statik modelinin kullanılamadığı durumlarda, SQL Server, iç içe geçmiş bir döngü birleşiminin önceki yinelemesinden bu yana ilişkili parametrelerden hiçbiri değişmediyse, msTVF tablo değişkenini kesmekten ve tekrar kullanmaktan kaçınabilir .
Bunu göstermek için, içeriğini T
beş özdeş i
değerle değiştireceğiz:
TRUNCATE TABLE dbo.T;
INSERT dbo.T (i)
VALUES (50005), (50005), (50005), (50005), (50005);
Yine ilişkili bir parametre ile sorgu:
SELECT T.i,
IR.n,
IR.ts
FROM dbo.T AS T
CROSS APPLY dbo.IntegerRange(1, T.i) AS IR
WHERE IR.n = T.i;
Bu kez sonuçlar yaklaşık 1,5 saniye içinde belirir :
Her satırdaki aynı zaman damgalarına dikkat edin. Tablo değişkenindeki önbelleklenmiş sonuç, ilişkili değerin i
değişmediği sonraki tekrarlamalar için tekrar kullanılır . Sonucun tekrar kullanılması her seferinde 50,005 satır eklemekten çok daha hızlıdır.
Uygulama planı öncekine çok benziyor:
Önemli fark, Tablo Değerli İşlev işlecinin Gerçek Yeniden Bağlamalar ve Gerçek Geri Sarmalar özelliklerindedir:
İlişkili parametreler değişmediğinde, SQL Server geçerli sonuçları tablo değişkeninde yeniden oynatabilir (geri sarabilir). Korelasyon değiştiğinde, SQL Server, tablo değişkenini kesmeli ve yeniden doldurmalıdır (yeniden bağlama). Bir isyan ilk iterasyonda olur; sonraki dört yineleme, değeri T.i
değişmediğinden geri sarar .