นี่ไม่ใช่คำตอบที่ยอมรับอย่างแน่นอน แต่ฉันสังเกตเห็นว่าสำหรับแผนการแบบสอบถามลูปซ้อนที่แสดงใน SQL Fiddle มันเป็นไปได้ที่จะใช้แผนจาก Query 2 ถึง Query 1 ด้วยการใช้USE PLAN
คำใบ้ แต่การพยายามย้อนกลับล้มเหลวด้วย
ตัวประมวลผลแบบสอบถามไม่สามารถสร้างแผนคิวรีได้เนื่องจากคำแนะนำการใช้ USE ประกอบด้วยแผนที่ไม่สามารถตรวจสอบได้ว่าถูกกฎหมายสำหรับคิวรี ลบหรือแทนที่คำแนะนำการใช้ USE PLAN เพื่อความเป็นไปได้ที่ดีที่สุดในการบังคับใช้แผนสำเร็จให้ตรวจสอบว่าแผนที่ระบุในคำแนะนำการใช้ USE Plan นั้นถูกสร้างขึ้นโดยอัตโนมัติโดย SQL Server สำหรับแบบสอบถามเดียวกัน
การปิดใช้งานกฎการแปลงเครื่องมือเพิ่มประสิทธิภาพ ReorderLOJN
จะป้องกันไม่ให้คำแนะนำแผนสำเร็จก่อนหน้านี้ประสบความสำเร็จเช่นกัน
การทดลองกับข้อมูลจำนวนมากแสดงให้เห็นว่า SQL Server นั้นสามารถแปลง(A LOJ B) LOJ C
เป็นA LOJ (B LOJ C)
ธรรมชาติได้อย่างแน่นอนเช่นกัน แต่ฉันไม่เห็นหลักฐานใด ๆ ที่ตรงกันข้ามว่าเป็นจริง
กรณีที่มีการวางแผนอย่างมากซึ่งแบบสอบถามแรกมีประสิทธิภาพดีกว่าแบบสอบถามที่สองคือ
DROP TABLE MyGrandChild , MyChild, MyParent
CREATE TABLE MyParent
(Id int)
CREATE TABLE MyChild
(Id int PRIMARY KEY
,ParentId int,
Filler char(8000) NULL)
CREATE TABLE MyGrandChild
(Id int
,ParentId int)
INSERT INTO MyChild
(Id, ParentId)
SELECT TOP (100000) ROW_NUMBER() OVER (ORDER BY @@SPID),
ROW_NUMBER() OVER (ORDER BY @@SPID)
FROM master..spt_values v1, master..spt_values
INSERT INTO MyGrandChild
(Id, ParentId)
OUTPUT INSERTED.Id INTO MyParent
SELECT TOP (3000) Id, Id AS ParentId
FROM MyChild
ORDER BY Id
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
SELECT gc.Id AS gcId,
gc.ParentId AS gcpId,
c.Id AS cId,
c.ParentId AS cpId,
p.Id AS pId
FROM MyGrandChild AS gc
LEFT OUTER JOIN MyChild AS c
ON c.[Id] = gc.[ParentId]
LEFT OUTER JOIN MyParent AS p
ON p.[Id] = c.[ParentId]
SELECT gc.Id AS gcId,
gc.ParentId AS gcpId,
c.Id AS cId,
c.ParentId AS cpId,
p.Id AS pId
FROM MyGrandChild AS gc
LEFT OUTER JOIN( MyChild AS c
LEFT OUTER JOIN MyParent AS p
ON p.[Id] = c.[ParentId])
ON c.[Id] = gc.[ParentId]
ซึ่งให้แผน
สำหรับฉัน Query 1 มีเวลาที่ผ่านไป 108 ms กับ 1,163 ms สำหรับ Query 2
แบบสอบถาม 1
Table 'Worktable'. Scan count 0, logical reads 0
Table 'MyChild'. Scan count 0, logical reads 9196
Table 'MyGrandChild'. Scan count 1, logical reads 7
Table 'MyParent'. Scan count 1, logical reads 5
แบบสอบถาม 2
Table 'MyParent'. Scan count 1, logical reads 15000
Table 'MyChild'. Scan count 0, logical reads 9000
Table 'MyGrandChild'. Scan count 1, logical reads 7
ดังนั้นจึงอาจสันนิษฐานว่าเป็นการชั่วคราวว่าไวยากรณ์แรก ("ไม่ถูกทดสอบ") อาจเป็นประโยชน์เนื่องจากอนุญาตให้พิจารณาคำสั่งซื้อที่มีศักยภาพมากขึ้น แต่ฉันยังไม่ได้ทำการทดสอบอย่างละเอียดเพียงพอที่จะมีความมั่นใจมากในเรื่องนี้ตามกฎทั่วไป
มันอาจเป็นไปได้ทั้งหมดที่จะเกิดขึ้นกับตัวอย่างเคาน์เตอร์ที่ Query 2 ทำงานได้ดีขึ้น ลองทั้งคู่และดูแผนการดำเนินการ