ฉันควรซ้อนภายนอกเข้าร่วมใน SQL Server หรือไม่


9

ฉันเคยได้ยินข้อมูลที่หลากหลายเกี่ยวกับเรื่องนี้และหวังว่าจะได้รับความเห็นที่เป็นที่ยอมรับหรือผู้เชี่ยวชาญ

หากฉันมีหลายรายการLEFT OUTER JOINแต่ละรายการขึ้นอยู่กับช่วงเวลาสุดท้ายมันจะดีกว่าไหมที่จะซ้อนมัน?

สำหรับตัวอย่างที่วางแผนที่JOINจะMyParentขึ้นอยู่กับJOINการMyChild: http://sqlfiddle.com/#!3/31022/5

SELECT
    {columns}
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]

ป้อนคำอธิบายรูปภาพที่นี่

เปรียบเทียบกับhttp://sqlfiddle.com/#!3/31022/7

SELECT
    {columns}
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]

ป้อนคำอธิบายรูปภาพที่นี่

ดังที่แสดงไว้ด้านบนเหล่านี้สร้างแผนการสืบค้นที่แตกต่างกันใน SS2k8


ฉันชอบใช้การรวมซ้อนกัน: michaeljswart.com/2012/09/when-i-use-nested-joinsอาจเป็นเรื่องของสไตล์
Michael J Swart

@MichaelJSwart บล็อกของคุณจะปรากฏขึ้นเพื่อหารือเกี่ยวกับเมื่อขึ้นอยู่กับJOINเป็นINNER JOIN
แมทธิว

1
คุณต้องการนิยาม "ดีกว่า" อย่างไร โดยส่วนตัวแล้วฉันพบว่าการอ่านครั้งแรกง่ายกว่ามาก - ใจของฉันไม่กระเด้งไปมาเพื่อพยายามพลิกผันความสัมพันธ์ มีON ... ONสองครั้งในแถว (วงเล็บหรือไม่) จะสับสนมาก
Aaron Bertrand

4
เมื่อฉันไม่พบความแตกต่างของการทำงานระหว่างสองวิธีในการทำบางสิ่งคำถามถัดไปที่ฉันถามตัวเองคือ: ถ้าฉันโดนรถบัสหรือชนะลอตเตอรีคืนนี้เวอร์ชันใดที่จะเข้าใจได้ง่ายที่สุด ?
Aaron Bertrand

1
use planคำใบ้ทำงานเมื่อปลูกแผนแบบสอบถามที่สองที่จะเป็นครั้งแรก แต่ไม่ได้ในทางกลับกัน
Martin Smith

คำตอบ:


3

นี่ไม่ใช่คำตอบที่ยอมรับอย่างแน่นอน แต่ฉันสังเกตเห็นว่าสำหรับแผนการแบบสอบถามลูปซ้อนที่แสดงใน 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 ทำงานได้ดีขึ้น ลองทั้งคู่และดูแผนการดำเนินการ


-1

ไม่มีประเภทการเข้าร่วมที่เรียกว่า "การเข้าร่วมที่ซ้อนกัน" เป็นอีกรูปแบบหนึ่งของการเขียน JOIN อาจใช้เพื่อความสะดวกในการอ่าน คุณสามารถเห็นพวกเขาเป็น "แบบสอบถามย่อย" เพื่อความเข้าใจเท่านั้น

หากคุณมีความกังวลมากขึ้นเกี่ยวกับการอ่านโค้ดได้สิ่งที่ฉันควรทำก็คือตัวเลือกของแต่ละคนที่พวกเขาจะยอมรับได้

และหากคุณกังวลเกี่ยวกับประสิทธิภาพของการสืบค้นและไม่ได้ใช้คำแนะนำ "การเข้าร่วมการสั่งซื้อ" ในการสืบค้นดังนั้นไม่สำคัญว่าการสืบค้นจะเขียนด้วยคำว่า "การเข้าร่วมที่ซ้อนกัน" หรือ "การเข้าร่วมภายนอกทั้งหมด" เซิร์ฟเวอร์ SQL คิดค่าใบสั่งตามค่าใช้จ่ายในการเข้าร่วมสองตารางและ / หรือผลลัพธ์ SQL Server ทำการ JOIN ระหว่างข้อมูลสองชุดในแต่ละครั้งเท่านั้น

ในความเป็นจริงลองคิดดูว่าในทางที่สอง "การรวมซ้อนกัน" ถ้าเซิร์ฟเวอร์ SQL ตัดสินใจที่จะทำส่วนที่สอง "MyChild AS c ด้านซ้ายด้านนอกเข้าร่วม MyParent AS p บนหน้า [id] = c [ParentId]" และตารางเหล่านั้นเกิดขึ้น มีแถวที่จะละทิ้งใน NEXT LEFT JOIN ในกรณีนั้นเซิร์ฟเวอร์ SQL ได้ใช้ทรัพยากรที่ไม่จำเป็นในการทำ OUTER JOIN ทั้งสองนี้และส่งผ่านผลลัพธ์นั้นไปยัง JOIN ถัดไป

คุณสามารถดูคำถามที่คล้ายกันที่ถามและตอบอย่างเหมาะสมที่นี่ ทำความเข้าใจกับไวยากรณ์ 'การเข้าร่วมที่ซ้อนกัน'


1
เพราะเหตุใดพวกเขาจึงสร้างแผนคิวรีที่แตกต่างกันโดยไม่ใช้FORCE JOIN ORDERคำใบ้?
แมทธิว

ด้วยคำใบ้นั้นเราไม่สามารถรับประกันคำสั่ง JOIN และในขณะที่คุณเห็นแผนการดำเนินการต่าง ๆ ที่พิสูจน์ได้ ตัวอย่างเช่นในวิธีแรก "ใช้ SQL ภายนอกทั้งหมด" เซิร์ฟเวอร์อาจทำสองสิ่งนี้ แรก "MyChild + MyGrandChild" แล้วเข้าร่วมกับ "MyParent" หรือแรก "MyChild + MyParent" จากนั้นเข้าร่วมกับ "MyGrandChild"
Anup Shah
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.