SQL Server 2012 dan 2016 Standar: Jika saya meletakkan logika if-else dalam prosedur tersimpan untuk mengeksekusi salah satu dari dua cabang kode, tergantung pada nilai parameter, apakah mesin cache versi terbaru?
Tidak, cache semua versi. Atau lebih tepatnya, cache satu versi dengan semua jalur dieksplorasi, dikompilasi dengan variabel yang diteruskan.
Ini demo singkat, menggunakan database Stack Overflow.
Buat indeks:
CREATE INDEX ix_yourmom ON dbo.Users (Reputation) INCLUDE (Id, DisplayName);
GO
Buat prosedur tersimpan dengan petunjuk indeks yang menunjuk ke indeks yang tidak ada, dalam kode bercabang.
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;
Jika saya menjalankan proc yang disimpan itu mencari Reputasi = 1, saya mendapatkan kesalahan.
EXEC dbo.YourMom @Reputation = 1;
Msg 308, Level 16, Status 1, Prosedur Youromom, Line 14 [Batch Start Line 32] Indeks 'ix_yourdad' pada tabel 'dbo.Users' (ditentukan dalam klausa FROM) tidak ada.
Jika kami memperbaiki nama indeks dan menjalankan kembali kueri, paket yang di- cache terlihat seperti ini:
Di dalam, XML akan memiliki dua referensi ke @Reputation
variabel.
<ColumnReference Column="@Reputation" ParameterDataType="int" ParameterCompiledValue="(1)" />
Tes yang sedikit lebih sederhana adalah dengan hanya mendapatkan perkiraan rencana untuk proc yang disimpan. Anda dapat melihat pengoptimal mengeksplorasi kedua jalur:
Dan jika pada eksekusi berikut, nilai parameter berubah, apakah ia akan mengkompilasi ulang dan me-cache kembali prosedur yang tersimpan, karena cabang kode yang berbeda harus dieksekusi? (Permintaan ini cukup mahal untuk dikompilasi.) Terima kasih.
Tidak, itu akan mempertahankan nilai runtime dari kompilasi pertama.
Jika kami menjalankan kembali dengan yang berbeda @Reputation
:
EXEC dbo.YourMom @Reputation = 2;
Dari rencana aktual :
<ColumnReference Column="@Reputation" ParameterDataType="int" ParameterCompiledValue="(1)" ParameterRuntimeValue="(2)" />
Kami masih memiliki nilai kompilasi 1, tapi sekarang nilai runtime 2.
Dalam cache rencana, yang dapat Anda periksa dengan alat gratis seperti yang dikembangkan perusahaan saya, sp_BlitzCache :
Prosedur tersimpan telah dipanggil dua kali, dan setiap pernyataan di dalamnya telah dipanggil sekali.
Jadi apa yang kita miliki? Satu paket cache untuk kedua pertanyaan dalam prosedur tersimpan.
Jika Anda ingin jenis logika bercabang ini, Anda harus memanggil prosedur yang tersimpan:
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;
Atau SQL dinamis:
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;
Semoga ini membantu!