ความคิดใดที่ว่าทำไมIF EXISTS
มันถึงทำให้มันใช้งานได้นานขึ้นและอ่านได้มากขึ้น? ฉันเปลี่ยนคำสั่ง select เป็นสิ่งที่ต้องทำSELECT TOP 1 [dlc].[id]
และฉันก็ฆ่ามันหลังจาก 2 นาที
ตามที่ฉันอธิบายในคำตอบของคำถามที่เกี่ยวข้องนี้:
TOP (และทำไม) ส่งผลกระทบต่อแผนการดำเนินการอย่างไร
การใช้EXISTS
แนะนำเป้าหมายของแถวซึ่งเครื่องมือเพิ่มประสิทธิภาพสร้างแผนการดำเนินการที่มุ่งหาที่ตั้งของแถวแรกอย่างรวดเร็ว ในการทำเช่นนี้จะถือว่าข้อมูลมีการกระจายอย่างสม่ำเสมอ ตัวอย่างเช่นหากสถิติแสดงว่ามีการจับคู่ที่คาดไว้ 100 รายการใน 100,000 แถวจะถือว่ามีการอ่านเพียง 1,000 แถวเพื่อค้นหาการจับคู่แรก
ซึ่งจะส่งผลในการดำเนินการนานกว่าที่คาดไว้หากข้อสันนิษฐานนี้เป็นความผิดพลาด ตัวอย่างเช่นหาก SQL Server เลือกวิธีการเข้าถึง (เช่นการสแกนแบบไม่มีการเรียงลำดับ) ที่เกิดขึ้นเพื่อค้นหาค่าการจับคู่แรกที่ล่าช้ามากในการค้นหาอาจส่งผลให้การสแกนเกือบสมบูรณ์ ในทางกลับกันหากพบแถวที่ตรงกันระหว่างสองสามแถวแรกประสิทธิภาพจะดีมาก นี่เป็นความเสี่ยงพื้นฐานที่มีเป้าหมายของแถว - ประสิทธิภาพที่ไม่สอดคล้องกัน
เป็นการแก้ไขชั่วคราวฉันได้ทำการเปลี่ยนแปลงเพื่อทำการนับ (*) และกำหนดค่าให้กับตัวแปร
โดยทั่วไปแล้วเป็นไปได้ที่จะจัดระเบียบคิวรีใหม่ซึ่งไม่ได้กำหนดเป้าหมายแถว หากไม่มีเป้าหมายแถวแบบสอบถามจะยังคงสิ้นสุดลงเมื่อพบแถวแรกที่ตรงกัน (ถ้าเขียนถูกต้อง) แต่กลยุทธ์แผนการดำเนินการมีแนวโน้มที่จะแตกต่างกัน (และหวังว่าจะมีประสิทธิภาพมากขึ้น) เห็นได้ชัดว่า count (*) จะต้องอ่านทุกแถวดังนั้นจึงไม่ใช่ทางเลือกที่สมบูรณ์แบบ
หากคุณใช้ SQL Server 2008 R2 หรือใหม่กว่าคุณสามารถใช้เอกสารที่ได้รับการสนับสนุนและสนับสนุนการตั้งค่าสถานะการสืบค้นกลับ 4138เพื่อรับแผนการดำเนินการโดยไม่มีเป้าหมายแถว นอกจากนี้ยังสามารถระบุการตั้งค่าสถานะนี้ได้โดยใช้คำใบ้ที่ได้รับ การสนับสนุนOPTION (QUERYTRACEON 4138)
แต่โปรดทราบว่ามันต้องได้รับอนุญาตดูแลระบบรันไทม์ยกเว้นว่าใช้กับคำแนะนำแผน
น่าเสียดาย
ไม่มีข้อใดถูกใช้งานได้กับIF EXISTS
ข้อความสั่งแบบมีเงื่อนไข ใช้กับ DML ปกติเท่านั้น มันจะทำงานกับSELECT TOP (1)
สูตรทางเลือกที่คุณลอง นั่นอาจจะดีกว่าการใช้COUNT(*)
งานซึ่งจะต้องนับจำนวนแถวที่ผ่านการรับรองตามที่ได้กล่าวไปแล้วทั้งหมด
ที่กล่าวว่ามีหลายวิธีที่จะแสดงความต้องการนี้ที่จะช่วยให้คุณหลีกเลี่ยงหรือควบคุมเป้าหมายแถวในขณะที่ยกเลิกการค้นหาก่อน หนึ่งตัวอย่างสุดท้าย:
DECLARE @Exists bit;
SELECT @Exists =
CASE
WHEN EXISTS
(
SELECT [dlc].[ID]
FROM TableDLC [dlc]
JOIN TableD [d]
ON [d].[ID] = [dlc].[ID]
JOIN TableC [c]
ON [c].[ID] = [d].[ID2]
WHERE [c].[Name] <> [dlc].[Name]
)
THEN CONVERT(bit, 1)
ELSE CONVERT(bit, 0)
END
OPTION (QUERYTRACEON 4138);
IF @Exists = 1
BEGIN
...
END;
IF NOT EXISTS (...) BEGIN END ELSE BEGIN <do something> END
-