Explicit vs implicit SQL joins


399

มีความแตกต่างของประสิทธิภาพในการรวมภายในอย่างชัดเจนกับนัยหรือไม่? ตัวอย่างเช่น:

SELECT * FROM
table a INNER JOIN table b
ON a.id = b.id;

เมื่อเทียบกับ

SELECT a.*, b.*
FROM table a, table b
WHERE a.id = b.id;

11
คำถามที่ดี. ฉันสงสัยว่าทำไมการเข้าร่วมที่ชัดเจนจึงถูกใช้ทั้งหมด มันเป็นไปไม่ได้ที่จะทำแบบสอบถามทั้งหมดโดยไม่ได้หรือไม่
Andrew

6
ใช้คำสำคัญอธิบายเพื่อทราบความแตกต่างเกี่ยวกับทั้งแบบสอบถาม .. ใช้เข้าร่วมและดูความแตกต่าง .. ถ้าคุณลองในตารางมากกว่า 100k บันทึกคุณสามารถเห็นความแตกต่าง ...
Jeyanth Kumar

@ andrew คำถามของฉันคือจริง ๆ ว่าการเข้าร่วมโดยนัยเป็นรูปแบบของ "แฮ็ค" (เช่นเดียวกับใน "แบบสอบถามที่มีมากกว่าหนึ่งตารางไม่ได้ใช้การเข้าร่วมหรือไม่นั่นคือแฮ็คไม่ใช่หรือ" ")
bobobobo

3
การเข้าร่วมโดยนัยจะทำให้คุณประหลาดใจทุกครั้งเมื่อจัดการกับค่า Null ใช้การเข้าร่วมอย่างชัดเจนและหลีกเลี่ยงข้อบกพร่องที่เกิดขึ้นเมื่อ "ไม่มีอะไรเปลี่ยนแปลง!"
BlackTigerX

1
ไม่มีความแตกต่าง ,เป็นCROSS JOINที่มีผลผูกพันและโยกINNER JOINเป็นCROSS JOINด้วยONเหมือนWHEREแต่ที่เข้มงวดมากขึ้นมีผลผูกพัน สิ่งที่สำคัญสำหรับการดำเนินการคือวิธีที่ DBMS ปรับการค้นหาให้เหมาะสม
philipxy

คำตอบ:


132

ประสิทธิภาพการทำงานที่ชาญฉลาดพวกเขาเหมือนกัน (อย่างน้อยใน SQL Server)

PS: โปรดทราบว่าIMPLICIT OUTER JOINไวยากรณ์เลิกใช้แล้วตั้งแต่ SQL Server 2005 ( IMPLICIT INNER JOINยังคงสนับสนุนไวยากรณ์ตามที่ใช้ในคำถาม)

การเลิกใช้งานไวยากรณ์ "แบบเก่า" ของ JOIN: เป็นเพียงบางส่วนเท่านั้น


4
@lomaxx เพียงเพื่อเห็นแก่ความชัดเจนของคุณสามารถระบุซึ่งไวยากรณ์ของ 2 ในคำถามที่จะเลิก?
J Wynia

8
คุณสามารถให้เอกสารสนับสนุนได้หรือไม่? ฟังดูผิดหลายระดับ
NotMe

21
คุณเลิกใช้มาตรฐาน SQL อย่างไร
David Crawshaw

7
@david Crenshaw การเข้าร่วมโดยนัยไม่ได้อยู่ในมาตรฐานอีกต่อไปและยังไม่ได้ผ่านไป 18 ปี
HLGEM

11
สิ่งที่เรียกว่า "การรวมโดยนัย" ของความหลากหลาย 'ภายใน' หรือ 'ข้าม' ยังคงอยู่ในมาตรฐาน SQL Server กำลังเลิกใช้ไวยากรณ์การรวมภายนอก "แบบเก่า" (เช่น*=และ=*) ซึ่งไม่เคยเป็นมาตรฐาน
oneday

129

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


4
ฉันเห็นด้วยอย่างยิ่ง แต่นี่เป็นหัวข้อนอกหัวข้อ OP ถามถึงประสิทธิภาพ
villasv

56

ใน MySQL 5.1.51 แบบสอบถามทั้งสองมีแผนการดำเนินการเหมือนกัน:

mysql> explain select * from table1 a inner join table2 b on a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.02 sec)

mysql> explain select * from table1 a, table2 b where a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.00 sec)

table1มี 166208 แถว table2มีประมาณ 1,000 แถว

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


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

37

ไวยากรณ์ที่สองมีความเป็นไปได้ที่ไม่พึงประสงค์ของการเข้าร่วมไขว้: คุณสามารถเพิ่มตารางลงในส่วน FROM โดยไม่ต้องมีคำสั่ง WHERE ที่เกี่ยวข้อง สิ่งนี้ถือว่าเป็นอันตราย


เกิดอะไรขึ้นถ้าชื่อตารางในส่วนคำสั่งถูกสร้างขึ้นจากตารางที่ใช้ในส่วนคำสั่งที่ไหน?
Jus12

คุณสามารถทำการ cross cross กับไวยากรณ์ JOIN ที่ชัดเจนได้เช่นกัน ( stackoverflow.com/a/44438026/929164 ) คุณอาจหมายถึงว่ามันเข้มงวดน้อยกว่าทำให้เกิดข้อผิดพลาดของผู้ใช้มากขึ้น
Daniel Dubovski

15

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

ฉันเห็นด้วยกับ grom ว่าคุณควรใช้ไวยากรณ์การเข้าร่วม ANSI ดังที่พวกเขาพูดเหตุผลหลักคือเพื่อความชัดเจน แทนที่จะมีส่วนคำสั่ง where ที่มีเพรดิเคตจำนวนมากซึ่งบางตารางเข้าร่วมและอื่น ๆ ที่ จำกัด แถวที่ส่งคืนด้วยไวยากรณ์การเข้าร่วม ANSI ที่คุณกำลังทำให้ชัดเจนว่าเงื่อนไขใดบ้างที่ถูกใช้เพื่อเข้าร่วมตารางของคุณ ผล.


5

ประสิทธิภาพการทำงานที่ชาญฉลาดพวกเขาเหมือนกัน (อย่างน้อยใน SQL Server) แต่โปรดระวังว่าพวกเขากำลังเลิกใช้ไวยากรณ์การเข้าร่วมนี้และไม่รองรับ sql server2005 นอกกรอบ

ฉันคิดว่าคุณกำลังคิดถึงตัวดำเนินการ * = และ = * ที่เทียบกับ "การรวมภายนอก"

ฉันเพิ่งทดสอบรูปแบบสองรูปแบบที่กำหนดและทำงานได้อย่างถูกต้องบนฐานข้อมูล SQL Server 2008 ในกรณีของฉันพวกเขาให้ผลแผนการดำเนินการที่เหมือนกัน แต่ฉันไม่สามารถพูดได้อย่างมั่นใจว่าสิ่งนี้จะเป็นจริงเสมอ


5

@ lomaxx: เพื่อชี้แจงฉันค่อนข้างมั่นใจว่าทั้งไวยากรณ์ข้างต้นได้รับการสนับสนุนโดย SQL Serv 2005 ไวยากรณ์ด้านล่างนี้ไม่ได้รับการสนับสนุน

select a.*, b.*  
from table a, table b  
where a.id *= b.id;

ไม่สนับสนุนการรวมภายนอก (* =)


2
ตรงไปตรงมาฉันจะไม่ใช้มันแม้แต่ใน SQL Server 2000 ไวยากรณ์ * = มักให้คำตอบที่ผิด บางครั้งมันตีความสิ่งเหล่านี้เป็นข้ามเข้าร่วม
HLGEM

2

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

คุณไม่ได้ระบุว่าคุณใช้ฐานข้อมูลใดอยู่ แต่ความน่าจะเป็นแนะนำให้ SQL Server หรือ MySQL ที่ซึ่งมันทำให้ไม่แตกต่างกันจริง


1
คุณสามารถใช้คำแนะนำในการเข้าร่วมโดยปริยายด้วยเช่นกัน
SquareCog

1
ใน Oracle นั้นหายากมากสำหรับการเข้าร่วมเพื่อส่งผลกระทบต่อแผนการดำเนินการในทางที่มีความหมาย ดูบทความนี้โดย Jonathan Lewis สำหรับคำอธิบาย
Jon Heller

1

ดังที่ Leigh Caldwell ได้กล่าวไว้เครื่องมือเพิ่มประสิทธิภาพการสืบค้นสามารถสร้างแผนการสืบค้นที่แตกต่างกันโดยขึ้นอยู่กับลักษณะการใช้งานที่ดูเหมือนคำสั่ง SQL เดียวกัน สำหรับการอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ให้ดูที่การโพสต์บล็อกสองรายการต่อไปนี้: -

การโพสต์เดียวจากทีม Oracle Optimizer Team

การโพสต์อื่นจากบล็อก "ข้อมูลที่มีโครงสร้าง"

ฉันหวังว่าคุณจะพบสิ่งที่น่าสนใจ


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

1

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


0

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

เมื่อจัดการกับการรวมภายในไม่มีความแตกต่างในการอ่านอย่างแท้จริงอย่างไรก็ตามมันอาจมีความซับซ้อนเมื่อจัดการกับการรวมซ้ายและขวาเหมือนกับวิธีเก่าที่คุณจะได้รับดังนี้:

SELECT * 
FROM table a, table b
WHERE a.id = b.id (+);

ด้านบนเป็นวิธีการเขียนการรวมด้านซ้ายแบบเดิมซึ่งตรงข้ามกับสิ่งต่อไปนี้:

SELECT * 
FROM table a 
LEFT JOIN table b ON a.id = b.id;

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

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


-1

จากประสบการณ์ของฉันการใช้ cross-join-with-a-where-clause syntax มักจะสร้างแผนการดำเนินการที่สมองเสียหายโดยเฉพาะถ้าคุณใช้ผลิตภัณฑ์ Microsoft SQL วิธีที่ SQL Server พยายามประมาณจำนวนแถวของตารางนั้นน่ากลัวอย่างยิ่ง การใช้ไวยากรณ์การรวมภายในช่วยให้คุณสามารถควบคุมวิธีการดำเนินการค้นหา ดังนั้นจากมุมมองที่ใช้งานได้จริงเนื่องจากธรรมชาติของเทคโนโลยีฐานข้อมูลปัจจุบันคุณต้องไปกับการรวมภายใน


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