แบบสอบถามย่อยเข้าร่วม


158

ฉันปรับโครงสร้างส่วนที่ช้าของแอปพลิเคชันที่เราสืบทอดจาก บริษัท อื่นให้ใช้การเข้าร่วมภายในแทนแบบสอบถามย่อยเช่น:

WHERE id IN (SELECT id FROM ...)

แบบสอบถามที่มีการปรับโครงสร้างใหม่จะทำงานได้เร็วขึ้นประมาณ 100x (~ 50 วินาทีถึง ~ 0.3) ฉันคาดว่าจะได้รับการปรับปรุง แต่ใคร ๆ ก็สามารถอธิบายได้ว่าทำไมมันถึงรุนแรง คอลัมน์ที่ใช้ในส่วนคำสั่ง where ถูกทำดัชนีทั้งหมด SQL ดำเนินการค้นหาในส่วนคำสั่ง where หนึ่งครั้งต่อแถวหรือบางอย่างหรือไม่?

อัปเดต - อธิบายผลลัพธ์:

ความแตกต่างอยู่ในส่วนที่สองของแบบสอบถาม "where id in ()" -

2   DEPENDENT SUBQUERY  submission_tags ref st_tag_id   st_tag_id   4   const   2966    Using where

vs 1 แถวที่จัดทำดัชนีโดยมีส่วนร่วม:

    SIMPLE  s   eq_ref  PRIMARY PRIMARY 4   newsladder_production.st.submission_id  1   Using index


2
ไม่ซ้ำกัน คำถามนี้โดยเฉพาะเกี่ยวกับความแตกต่างของประสิทธิภาพที่โดดเด่น คำถามอื่น ๆ เป็นคำถามทั่วไปที่เปิดกว้างเกี่ยวกับข้อดีข้อเสียของแต่ละวิธี
Basil Bourque

@simhumileco นั่นคือการปรับปรุงไม่ได้ไม่มีความแตกต่างมันเป็นสิ่งที่ตรงกันข้ามกับสิ่งที่ผู้เขียนเขียนและการแก้ไขรูปแบบโค้ดนั้นไม่เหมาะสม ฉันควรแก้ไขโค้ดเมื่อใด
philipxy

สวัสดี @philipxy ฉันไม่ได้ตั้งใจที่จะแทรกแซงความคิดของผู้เขียน แต่เพียงเพื่อให้ส่วนของโค้ดอ่านง่ายขึ้นและเขียนอย่างระมัดระวังยิ่งขึ้น
simhumileco

คำตอบ:


160

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

แต่ใช่แผนอธิบายจะให้รายละเอียดสกปรกแก่คุณ


3
โปรดทราบว่าDEPENDENT SUBQUERYหมายถึงสิ่งเดียวกันกับ "แบบสอบถามย่อยที่สัมพันธ์กัน"
Timo

38

คุณกำลังเรียกใช้แบบสอบถามย่อยหนึ่งครั้งสำหรับทุกแถวในขณะที่การเข้าร่วมเกิดขึ้นกับดัชนี


5
ฉันไม่คิดว่านี่เป็นเรื่องจริง เอ็นจิน SQL ควรรันเคียวรีย่อยเพียงครั้งเดียวและใช้ผลลัพธ์เป็นรายการ
dacracot

8
ขึ้นอยู่กับว่า - หากแบบสอบถามย่อยมีความสัมพันธ์กับแบบสอบถามด้านนอกอย่างใด (ใช้ข้อมูล) มันจะถูกดำเนินการกับแต่ละแถว
qbeuek

4
มันอาจเป็นจริงในกรณีนี้ แต่โดยทั่วไปไม่ได้
Amy B

1
OP EXPLAINกล่าวว่าDEPENDENT SUBQUERYซึ่งเป็นตัวบ่งชี้ที่ชัดเจนที่สุดของพฤติกรรมนี้
ติโม

16

นี่คือตัวอย่างของวิธีการที่subqueries ได้รับการประเมินใน MySQL 6.0

เครื่องมือเพิ่มประสิทธิภาพใหม่จะแปลงแบบสอบถามย่อยประเภทนี้เป็นการรวม


นั่นเป็นบทความดีดีใน MySQL 6.0 การปรับปรุงเพิ่มประสิทธิภาพขอบคุณ
ไฟอีกา

7

เรียกใช้การอธิบายแผนในแต่ละรุ่นมันจะบอกคุณว่าทำไม


6

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

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


4

ดูแผนแบบสอบถามสำหรับแต่ละแบบสอบถาม

ที่ไหนในและเข้าร่วมสามารถมักจะได้รับการดำเนินการโดยใช้แผนปฏิบัติการเดียวกันดังนั้นโดยทั่วไปจะมีค่าเป็นศูนย์ความเร็วเพิ่มขึ้นจากการเปลี่ยนแปลงระหว่างพวกเขา


3
ฮ่าฮ่าฉัน <3 ตรว. ลงคะแนนนั้นเพราะพวกเขาไม่รู้วิธีอ่านแผนแบบสอบถาม
เอมี่ B

4

เครื่องมือเพิ่มประสิทธิภาพทำงานได้ไม่ดีนัก โดยปกติแล้วพวกเขาสามารถแปลงได้โดยไม่มีความแตกต่างและเครื่องมือเพิ่มประสิทธิภาพสามารถทำได้


4

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


4

คำถามนี้ค่อนข้างทั่วไปดังนั้นนี่เป็นคำตอบทั่วไป:

โดยทั่วไปเคียวรีจะใช้เวลานานขึ้นเมื่อ MySQL มีจำนวนแถวเรียงกันเป็นแถว

ทำเช่นนี้:

เรียกใช้คำอธิบายในแบบสอบถามแต่ละรายการ (รายการที่รวมแล้วจากรายการย่อย) และโพสต์ผลลัพธ์ที่นี่

ฉันคิดว่าการเห็นความแตกต่างในการตีความ MySQL ของข้อความค้นหาเหล่านั้นจะเป็นประสบการณ์การเรียนรู้สำหรับทุกคน


4

เคียวรีย่อย where ต้องรัน 1 เคียวรีสำหรับแต่ละแถวที่ส่งคืน การรวมภายในมีเพียงการเรียกใช้ 1 แบบสอบถาม


3

ข้อความค้นหาย่อยอาจใช้ "การสแกนแบบเต็มตาราง" กล่าวอีกนัยหนึ่งไม่ได้ใช้ดัชนีและส่งคืนแถวมากเกินไปซึ่งจำเป็นต้องกรองออกจากที่ไหน

แค่เดาโดยไม่มีรายละเอียดแน่นอน แต่นั่นเป็นสถานการณ์ทั่วไป


2

ด้วยเคียวรีย่อยคุณต้องเรียกใช้งาน SELECT อีกครั้งสำหรับแต่ละผลลัพธ์และโดยปกติแล้วการดำเนินการแต่ละครั้งจะส่งคืน 1 แถว

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


2

มันไม่ได้เป็นคำถามย่อยมากนักตามข้อ IN แม้ว่าการรวมจะเป็นพื้นฐานของเอ็นจิน SQL อย่างน้อยของ Oracle และทำงานได้อย่างรวดเร็วมาก


1
ในที่ที่ไม่ได้เลวร้ายจริงๆ
Shawn

2

นำมาจากคู่มืออ้างอิง ( 14.2.10.11 การสืบค้นย่อยการสืบค้นใหม่เป็นร่วม ):

LEFT [OUTER] JOIN สามารถเร็วกว่าแบบสอบถามย่อยที่เทียบเท่าได้เนื่องจากเซิร์ฟเวอร์อาจสามารถปรับให้เหมาะสมได้ดีกว่าความจริงที่ไม่เฉพาะเจาะจงกับเซิร์ฟเวอร์ MySQL เพียงอย่างเดียว

ดังนั้นเคียวรีย่อยอาจช้ากว่า LEFT [OUTER] JOINS

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