SQL Server 2012 และ 2016 มาตรฐาน: ถ้าฉันใส่ตรรกะ if-else ในกระบวนงานที่เก็บไว้เพื่อเรียกใช้โค้ดหนึ่งในสองสาขาขึ้นอยู่กับค่าพารามิเตอร์พารามิเตอร์เอ็นจินแคชเป็นเวอร์ชันล่าสุดหรือไม่
ไม่แคชทุกรุ่น หรือมากกว่านั้นจะเก็บรุ่นหนึ่งโดยมีการสำรวจเส้นทางทั้งหมดรวบรวมด้วยตัวแปรที่ส่งผ่าน
นี่คือตัวอย่างด่วนโดยใช้ฐานข้อมูล Stack Overflow
สร้างดัชนี:
CREATE INDEX ix_yourmom ON dbo.Users (Reputation) INCLUDE (Id, DisplayName);
GO
สร้างโพรซีเดอร์ที่เก็บด้วยคำใบ้ดัชนีซึ่งชี้ไปยังดัชนีที่ไม่มีอยู่ในโค้ดที่แยกสาขา
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;
ถ้าฉันเรียกใช้ proc ที่เก็บไว้นั้นกำลังมองหา Reputation = 1 ฉันจะได้รับข้อผิดพลาด
EXEC dbo.YourMom @Reputation = 1;
ข่าวสารเกี่ยวกับ 308, ระดับ 16, สถานะ 1, ขั้นตอน YourMom, บรรทัดที่ 14 [Batch Start Line 32] ดัชนี 'ix_yourdad' บนตาราง 'dbo.Users' (ไม่มีอยู่ในส่วนคำสั่ง FROM)
หากเราแก้ไขชื่อดัชนีและเรียกใช้แบบสอบถามอีกครั้งแผนแคชจะมีลักษณะดังนี้:
ภายใน XML จะมีการอ้างอิงสอง@Reputation
ตัวแปร
<ColumnReference Column="@Reputation" ParameterDataType="int" ParameterCompiledValue="(1)" />
การทดสอบที่ง่ายกว่าเล็กน้อยคือเพียงแค่ได้รับการประมาณแผนสำหรับ proc ที่เก็บไว้ คุณสามารถดูเครื่องมือเพิ่มประสิทธิภาพสำรวจทั้งสองเส้นทาง:
และถ้าในการดำเนินการต่อไปนี้ค่าของพารามิเตอร์จะเปลี่ยนแปลงมันจะรวบรวมและแคชกระบวนการที่เก็บไว้อีกครั้งเพราะสาขาที่แตกต่างกันของรหัสจะต้องดำเนินการหรือไม่ (แบบสอบถามนี้มีราคาค่อนข้างสูงในการรวบรวม) ขอบคุณ
ไม่มันจะเก็บค่ารันไทม์ของการคอมไพล์ครั้งแรก
หากเราเรียกใช้งานอีกครั้งด้วย@Reputation
:
EXEC dbo.YourMom @Reputation = 2;
จากแผนจริง :
<ColumnReference Column="@Reputation" ParameterDataType="int" ParameterCompiledValue="(1)" ParameterRuntimeValue="(2)" />
เรายังคงมีค่าที่คอมไพล์เป็น 1 แต่ตอนนี้เป็นค่ารันไทม์เป็น 2
ในแคชแผนซึ่งคุณสามารถตรวจสอบด้วยเครื่องมือฟรีเช่นเดียวกับที่ บริษัท ของฉันพัฒนาsp_BlitzCache :
กระบวนงานที่เก็บไว้ถูกเรียกสองครั้งและแต่ละคำสั่งในนั้นถูกเรียกหนึ่งครั้ง
แล้วเรามีอะไร แผนแคชหนึ่งแบบสอบถามทั้งสองในขั้นตอนการจัดเก็บ
หากคุณต้องการตรรกะแยกประเภทนี้คุณจะต้องเรียกขั้นตอนการจัดเก็บย่อย:
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;
หรือ 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;
หวังว่านี่จะช่วยได้!