SQL Server 2012 ve 2016 Standardı: Bir parametrenin değerine bağlı olarak iki kod dalından birini yürütmek için if-else mantığını saklı bir yordama koyarsam, motor en son sürümü önbelleğe alıyor mu?
Hayır, tüm sürümleri önbelleğe alır . Daha doğrusu, değişkenleri iletilenlerle derlenen, keşfedilen tüm yolları içeren bir sürümü önbelleğe alır .
İşte Stack Overflow veritabanını kullanarak hızlı bir demo.
Bir dizin oluşturun:
CREATE INDEX ix_yourmom ON dbo.Users (Reputation) INCLUDE (Id, DisplayName);
GO
Dallanmayan kodda, var olmayan bir dizine işaret eden bir dizin ipucu ile saklı bir yordam oluşturun.
CREATE OR ALTER PROCEDURE dbo.YourMom (@Reputation INT)
AS
BEGIN
IF @Reputation = 1
BEGIN
SELECT u.Id, u.DisplayName, u.Reputation
FROM dbo.Users AS u WITH (INDEX = PK_Users_Id)
WHERE u.Reputation = @Reputation;
END;
IF @Reputation > 1
BEGIN
SELECT u.Id, u.DisplayName, u.Reputation
FROM dbo.Users AS u WITH (INDEX = ix_yourdad)
WHERE u.Reputation = @Reputation;
END;
END;
Eğer depolanan proc Reputation = 1 arıyor yürütürsem, bir hata alıyorum.
EXEC dbo.YourMom @Reputation = 1;
Msg 308, Seviye 16, Durum 1, Yordam YourMom, Satır 14 [Toplu Başlangıç Satırı 32] 'dbo.Users' tablosundaki 'ix_yourdad' dizini (FROM yan tümcesinde belirtilen) mevcut değil.
Dizin adını düzeltir ve sorguyu yeniden çalıştırırsak, önbelleğe alınan plan aşağıdaki gibi görünür:
İçeride, XML @Reputation
değişken için iki referansa sahip olacaktır .
<ColumnReference Column="@Reputation" ParameterDataType="int" ParameterCompiledValue="(1)" />
Biraz daha basit bir test, depolanan proc için tahmini bir plan elde etmek olacaktır. Optimize edicinin her iki yolu da keşfettiğini görebilirsiniz:
Ve aşağıdaki yürütmede, parametrenin değeri değişirse, kodun farklı bir dalı yürütülmesi gerektiği için saklı yordamı yeniden derleyip yeniden önbelleğe alacak mı? (Bu sorguyu derlemek oldukça pahalıdır.) Teşekkürler.
Hayır, ilk derlemenin çalışma zamanı değerini korur.
Farklı bir yöntemle yeniden çalıştırırsak @Reputation
:
EXEC dbo.YourMom @Reputation = 2;
Gönderen gerçek planı :
<ColumnReference Column="@Reputation" ParameterDataType="int" ParameterCompiledValue="(1)" ParameterRuntimeValue="(2)" />
Derlenmiş 1 değerine sahibiz, ancak şimdi 2 çalışma zamanı değerine sahibiz.
Şirketimin geliştirdiği gibi ücretsiz bir araçla kontrol edebileceğiniz plan önbelleğinde, sp_BlitzCache :
Saklı yordam iki kez çağrıldı ve içindeki her ifade bir kez çağrıldı.
Peki neyimiz var? Saklı yordamda her iki sorgu için bir önbellek planı.
Eğer varsa istediğiniz dallı mantık bu tür, sen alt saklı yordamlar demelisiniz:
CREATE OR ALTER PROCEDURE dbo.YourMom (@Reputation INT)
AS
BEGIN
IF @Reputation = 1
BEGIN
EXEC dbo.Reputation1Query;
END;
IF @Reputation > 1
BEGIN
EXEC dbo.ReputationGreaterThan1Query;
END;
END;
Veya dinamik SQL:
DECLARE @sql NVARCHAR(MAX) = N''
SET @sql +=
N'
SELECT u.Id, u.DisplayName, u.Reputation
FROM dbo.Users AS u '
IF @Reputation = 1
BEGIN
SET @sql += N' (INDEX = PK_Users_Id)
WHERE u.Reputation = @Reputation;'
END;
IF @Reputation > 1
BEGIN
SET @sql += ' WITH (INDEX = ix_yourmom)
WHERE u.Reputation = @Reputation;'
END;
EXEC sys.sp_executesql @sql;
Bu yardımcı olur umarım!