สภาพภายใน JOIN หรือ WHERE


194

มีความแตกต่าง (ประสิทธิภาพการปฏิบัติที่ดีที่สุด ฯลฯ ... ) ระหว่างการวางเงื่อนไขในข้อเข้าร่วมกับข้อไหน?

ตัวอย่างเช่น...

-- Condition in JOIN
SELECT *
FROM dbo.Customers AS CUS
INNER JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
AND CUS.FirstName = 'John'

-- Condition in WHERE
SELECT *
FROM dbo.Customers AS CUS
INNER JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE CUS.FirstName = 'John'

คุณชอบแบบไหน (และอาจเป็นเพราะเหตุใด)


4
คุณเรียกใช้แบบสอบถามทั้งสองนี้หรือไม่ คุณตรวจสอบแผนการดำเนินการที่เกิดจากคำค้นหาสองคำหรือไม่ คุณสังเกตอะไร
S.Lott

22
@ S.Lott แบบสอบถามนี้มีวัตถุประสงค์เพื่อเป็นตัวอย่างเท่านั้น ฉันแค่สงสัยว่า "โดยทั่วไป" ซึ่งเป็นวิธีที่ต้องการ - ถ้ามี
Steve Dignan

1
@Steve Dignan: คุณควรทำการเปรียบเทียบด้วยข้อมูลตัวอย่างและดูที่แผนการสืบค้น คำตอบจะชัดเจนมาก และ - โบนัส - คุณจะมีโค้ดหนึ่งชิ้นที่คุณสามารถนำมาใช้ใหม่ได้เมื่อเกิดสถานการณ์ที่ซับซ้อนมากขึ้น
S.Lott

1
ฉันจะใส่เงื่อนไขในข้อเข้าร่วมโดยส่วนตัวถ้าเงื่อนไขอธิบายถึงความสัมพันธ์ เงื่อนไขทั่วไปที่เพิ่งกรองชุดผลลัพธ์จะไปที่ส่วนที่แล้ว เช่นFROM Orders JOIN OrderParties ON Orders.Id = OrderParties.Order AND OrderParties.Type = 'Recipient' WHERE Orders.Status = 'Canceled'
Glutexo

คำตอบ:


154

พีชคณิตเชิงสัมพันธ์ช่วยให้การเปลี่ยนค่าของเพรดิเคตในWHEREclause และ the INNER JOINดังนั้นแม้แต่INNER JOINเคียวรีที่มีWHEREclauses สามารถมีเพรดิเคตที่จัดเรียงใหม่โดย optimizer เพื่อให้พวกเขาอาจถูกแยกออกระหว่างJOINกระบวนการ

ฉันขอแนะนำให้คุณเขียนข้อความค้นหาในวิธีที่สามารถอ่านได้มากที่สุด

บางครั้งสิ่งนี้รวมถึงการทำให้INNER JOIN"ค่อนข้างไม่สมบูรณ์" และวางหลักเกณฑ์บางอย่างไว้ในWHEREเพียงเพื่อทำให้รายการของเกณฑ์การกรองง่ายขึ้น

ตัวอย่างเช่นแทนที่จะเป็น:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
    AND c.State = 'NY'
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
    AND a.Status = 1

เขียน:

SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
    ON ca.CustomerID = c.CustomerID
INNER JOIN Accounts a
    ON ca.AccountID = a.AccountID
WHERE c.State = 'NY'
    AND a.Status = 1

แต่แน่นอนว่าขึ้นอยู่กับ


7
มันไม่เพียงเกี่ยวกับการค้นหาที่สะอาดหรือการอ่านเท่านั้น แต่ยังเกี่ยวกับประสิทธิภาพ การใส่เงื่อนไขในการเข้าร่วมปรับปรุงประสิทธิภาพสำหรับข้อมูลจำนวนมากด้วยตารางที่จัดทำดัชนีอย่างเหมาะสม
Shahdat

1
ฉันเพิ่งเรียกใช้รายงานการขายรายเดือนเข้าร่วม 5-6 ตารางในบันทึกไม่กี่ล้าน Perf เพิ่มขึ้น 30% - sql server 2012
Shahdat

2
@Shahdat หากคุณได้รับความแตกต่างอย่างมีนัยสำคัญของประสิทธิภาพการย้ายเงื่อนไขตัวกรองของคุณจากที่ส่วนคำสั่งเพื่อเข้าร่วมภายในคุณต้องโพสต์แผนการดำเนินการเหล่านั้น
เคดรูส์

4
@Cade ฉันตรวจสอบแผนการดำเนินการแล้ว - ทั้งสองสถานการณ์แสดงต้นทุนเดียวกัน ฉันเรียกใช้แบบสอบถามหลายครั้งดูเหมือนว่าทั้งสองใช้เวลาประมาณเดียวกัน ก่อนหน้านี้ฉันใช้คำสั่งในการผลิตและมีความแตกต่างด้านประสิทธิภาพอย่างมากเนื่องจากมีการใช้ฐานข้อมูลโดยผู้ใช้จริง ขออภัยในความสับสนนั้น
Shahdat

4
คำตอบนี้เหมาะสำหรับการเข้าร่วมภายใน แต่ไม่ใช่สำหรับการเข้าร่วมซ้าย / ขวา
sotn

123

สำหรับการเข้าร่วมภายในฉันไม่ได้สังเกตเห็นความแตกต่าง (แต่เช่นเดียวกับการปรับประสิทธิภาพทั้งหมดคุณต้องตรวจสอบกับฐานข้อมูลของคุณภายใต้เงื่อนไขของคุณ)

อย่างไรก็ตามที่คุณใส่เงื่อนไขสร้างความแตกต่างอย่างมากถ้าคุณใช้การรวมซ้ายหรือขวา ยกตัวอย่างเช่นพิจารณาทั้งสองแบบสอบถาม:

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderDate >'20090515'

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
AND ORD.OrderDate >'20090515'

ครั้งแรกที่จะให้คุณบันทึกเฉพาะผู้ที่มีคำสั่งลงวันที่หลังจาก 15 พฤษภาคม 2009 จึงแปลงการเข้าร่วมด้านซ้ายเพื่อเข้าร่วมภายใน

ประการที่สองจะให้บันทึกเหล่านั้นรวมถึงลูกค้าที่ไม่มีคำสั่งซื้อ ชุดผลลัพธ์นั้นแตกต่างกันมากขึ้นอยู่กับว่าคุณใส่เงื่อนไขไว้ที่ใด (เลือก * ใช้เพื่อเป็นตัวอย่างเท่านั้นแน่นอนว่าคุณไม่ควรใช้สิ่งนี้ในรหัสการผลิต)

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

SELECT *
FROM dbo.Customers AS CUS 
LEFT JOIN dbo.Orders AS ORD 
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderID is null

ขอบคุณที่อธิบายด้วยตัวอย่าง
เรนนิชโจเซฟ

1
"จึงเปลี่ยนการรวมด้านซ้ายเป็นการรวมภายใน" อย่างไร? คุณอธิบายรายละเอียดเล็กน้อยได้ไหม?
user1451111

@ user1451111 เรียนรู้สิ่งที่ LEFT / RIGHT JOIN ส่งคืน: แถว INNER JOIN บวกกับแถวของตารางซ้าย / ขวาที่ไม่ตรงกันซึ่งขยายเป็น NULL FULL JOIN ส่งคืนแถวภายในเข้าร่วม UNION ทั้งหมดแถวด้านซ้ายและด้านขวาของตารางที่ไม่ตรงกันซึ่งขยายโดย NULLs มักจะรู้ว่าสิ่งที่เข้าร่วมภายในที่คุณต้องการเป็นส่วนหนึ่งของการเข้าร่วมด้านนอก WHERE หรือ ON ที่ต้องการคอลัมน์ NULL-Extended อาจจะไม่ใช่ NULL หลังจาก OUTER JOIN ON ลบแถวใด ๆ ที่ NULL ขยายออกนั่นคือปล่อยเฉพาะแถว INNER JOIN เท่านั้นเช่น "เปลี่ยน OINTER JOIN เป็น INNER JOIN"
philipxy

1
@ user1451111 หรือในแง่ง่ายกว่า: A left join Bคือทุกแถวจาก A เข้าร่วมกับทุกแถวที่ตรงกันจาก B หาก B ไม่มีแถวที่ตรงกันดังนั้นคอลัมน์ A มีค่า แต่ทุกคอลัมน์จาก B ในแถวนั้นแสดงเป็นค่า NULL หากคุณเขียนwhere B.somecolumn = ‘somevalue’คุณจะมีค่า NULL (B.somecolumn) ถูกเปรียบเทียบกับ 'somevalue' อะไรก็ตามที่เปรียบเทียบกับ NULL นั้นเป็นเท็จดังนั้นแถวทั้งหมดของคุณที่ไม่มีแถว B ที่ตรงกันสำหรับแถว A จะถูกตัดออกและผลลัพธ์ที่คุณได้รับจะเหมือนกับ INNER JOIN ที่จะให้ดังนั้นการเข้าร่วมด้านนอกจึงกลายเป็นหนึ่งใน
Caius Jard

ผลการใช่ผมได้ตรวจสอบเหมือนกันสำหรับ: funds.id SELECT, prospects.id จากfundsภายในเข้าร่วมในกลุ่มเป้าหมาย (prospects.id = funds.lead_id และ prospects.is_manual = 'ไม่') และ funds.id SELECT, prospects.id จากfundsซ้าย เข้าร่วมในกลุ่มเป้าหมาย (prospects.id = funds.lead_id) ที่ prospects.is_manual = 'ไม่'
Rohit Dhiman

25

ผลิตภัณฑ์ RDBMS ส่วนใหญ่จะปรับทั้งข้อความค้นหาให้เหมือนกัน ใน "การปรับแต่งประสิทธิภาพของ SQL" โดย Peter Gulutzan และ Trudy Pelzer พวกเขาทดสอบ RDBMS หลายยี่ห้อและไม่พบความแตกต่างด้านประสิทธิภาพ

ฉันต้องการแยกเงื่อนไขการเข้าร่วมออกจากเงื่อนไขการ จำกัด การสืบค้น

หากคุณกำลังใช้OUTER JOINบางครั้งก็จำเป็นต้องใส่เงื่อนไขไว้ในข้อเข้าร่วม


1
ฉันเห็นด้วยกับคุณว่า syntactically มันสะอาดขึ้นและฉันต้องเลื่อนความรู้ของคุณของหนังสือเล่มนี้และชื่อเสียงที่สูงมากของคุณ แต่ฉันสามารถคิดถึง 4 ข้อความค้นหาในสัปดาห์ที่แล้วด้วยแผนการดำเนินการที่แตกต่างกันมากเวลา CPU และตรรกะอ่านเมื่อ ฉันย้ายที่เพรดิเคตไปที่การเข้าร่วม
marr75

2
คุณถามเกี่ยวกับแนวทางปฏิบัติที่ดีที่สุด ทันทีที่คุณเข้าสู่การทดสอบวิธีการใช้งานของ RDBMS เฉพาะบุคคลอื่น ๆ ก็จะได้รับคำแนะนำที่ถูกต้องนั่นคือมาตรฐาน
Bill Karwin

12

ที่ใดจะกรองหลังจากเกิดการเข้าร่วม

กรองใน JOIN เพื่อป้องกันไม่ให้เพิ่มแถวในระหว่างกระบวนการเข้าร่วม


10
พวกเขาถูกป้องกันในระหว่างกระบวนการเข้าร่วมภายใน แต่เครื่องมือเพิ่มประสิทธิภาพสามารถจัดเรียงใหม่เข้าร่วมและสถานที่ที่จะแสดงความประสงค์ดังนั้นเพิ่มประสิทธิภาพเป็นอิสระที่จะแยกพวกเขาในภายหลังหากต้องการ
เคด Roux

1
เคดรูส์: ถูกต้อง บ่อยครั้งที่สิ่งที่คุณเขียนใน SQL ไม่ใช่เครื่องมือเพิ่มประสิทธิภาพที่จะให้คุณเมื่อทุกคนพูดและทำ ฉันจะคิดแล้วว่าเรื่องนี้จะได้รับสิทธิในโลกที่ทุกทฤษฎีในขณะที่คำตอบของคุณคือการเรียนที่ถูกต้องมากขึ้นในโลกของการเพิ่มประสิทธิภาพแบบสอบถามอัตโนมัติ :)
TheTXI

ฉันชอบคำอธิบายของเงื่อนไขในON
Robert Rocha

3

ฉันชอบ JOIN ที่จะเข้าร่วมตารางเต็ม / มุมมองแล้วใช้ WHERE เพื่อแนะนำภาคแสดงของชุดผลลัพธ์

มันรู้สึกสะอาดขึ้น


2

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

ฉันมักจะขบขันอย่างอ่อนโยนเมื่อมีคนแสดงการเปรียบเทียบ SQL ของพวกเขาและพวกเขาได้ดำเนินการทั้ง sproc 50,000 ครั้งในเวลาเที่ยงคืนบนเซิร์ฟเวอร์ dev และเปรียบเทียบเวลาเฉลี่ย


0

การใส่เงื่อนไขในการเข้าร่วมดูเหมือนว่า "ผิดเชิงความหมาย" สำหรับฉันเพราะนั่นไม่ใช่สิ่งที่ JOIN ทำเพื่อ "" แต่คุณภาพมาก

ปัญหาเพิ่มเติม: หากคุณตัดสินใจที่จะเปลี่ยนจากการเข้าร่วมภายในเป็นพูดเข้าร่วมที่ถูกต้องโดยมีเงื่อนไขอยู่ใน JOIN อาจนำไปสู่ผลลัพธ์ที่ไม่คาดคิด


3
บางครั้งผลลัพธ์เหล่านี้ค่อนข้าง "คาดหวัง" และบางครั้งแม้แต่ "เจตนา" (ตัวอย่างเช่นการรวมภายนอกซึ่งเงื่อนไขที่มีความหมายที่แตกต่างจากเงื่อนไขการเข้าร่วม)
Marcel Toth

0

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


-4

มันจะดีกว่าที่จะเพิ่มเงื่อนไขในการเข้าร่วม ประสิทธิภาพมีความสำคัญมากกว่าความสามารถในการอ่าน สำหรับชุดข้อมูลขนาดใหญ่มันสำคัญ


1
คุณมีข้อพิสูจน์บางอย่างหรือไม่วิจัยว่าตำแหน่งของภาคแสดงที่มีผลต่อประสิทธิภาพหรือไม่
Zso
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.