SQL เข้าร่วมกับแบบสอบถามย่อยของ SQL (ประสิทธิภาพ)?


110

ฉันต้องการทราบว่าฉันมีแบบสอบถามเข้าร่วมบางอย่างเช่นนี้ -

Select E.Id,E.Name from Employee E join Dept D on E.DeptId=D.Id

และแบบสอบถามย่อยเช่นนี้ -

Select E.Id,E.Name from Employee Where DeptId in (Select Id from Dept)

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

มีเวลาที่ควรชอบมากกว่ากันไหม?

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


5
@Lucero คำถามนี้ติดแท็ก sql-server-2008 โดยที่โพสต์ที่คุณพูดถึงมีแท็ก MySql คุณสามารถอนุมานได้ว่าคำตอบจะเหมือนกัน การเพิ่มประสิทธิภาพการทำงานจะแตกต่างกันไปใน RDBMS สองตัว
Francois Botha

คำตอบ:


48

ฉันจะคาดหวังว่าแบบสอบถามแรกจะเร็วกว่าส่วนใหญ่เป็นเพราะคุณมีความเท่าเทียมกันและการเข้าร่วมที่ชัดเจน จากประสบการณ์ของฉันINเป็นตัวดำเนินการที่ช้ามากเนื่องจากโดยปกติ SQL จะประเมินเป็นชุดของWHEREประโยคที่คั่นด้วย "OR" ( WHERE x=Y OR x=Z OR...)

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

วิธีเดียวที่จะบอกได้อย่างมั่นใจ 100% ซึ่งเร็วกว่าคือการเปิดการติดตามประสิทธิภาพ (สถิติ IO มีประโยชน์อย่างยิ่ง) และเรียกใช้ทั้งสองอย่าง อย่าลืมล้างแคชระหว่างวิ่ง!


16
ฉันมีข้อสงสัยอย่างมากเกี่ยวกับคำตอบนี้เนื่องจาก DBMS ส่วนใหญ่ซึ่งแน่นอนว่าเป็น SQL Server 2008 และใหม่กว่าให้แปลแบบสอบถามย่อย ID เดียว (ไม่สัมพันธ์กันหมายความว่า: ไม่อ้างอิงคอลัมน์แบบสอบถามภายนอกหลายคอลัมน์) เป็นการรวมกึ่งรวดเร็ว นอกจากนี้ตามที่ระบุไว้ก่อนหน้านี้ในคำตอบอื่นการรวมจริงครั้งแรกจะส่งคืนแถวสำหรับ EACH ที่เกิดขึ้นของ ID ที่ตรงกันในแผนกซึ่งไม่ทำให้เกิดความแตกต่างสำหรับ ID ที่ไม่ซ้ำกัน แต่จะทำให้คุณมีรายการซ้ำจำนวนมากที่อื่น การจัดเรียงสิ่งเหล่านี้ด้วย DISTINCT หรือ GROUP BY จะเป็นอีกหนึ่งภาระงานหนัก ตรวจสอบแผนการดำเนินการใน SQL Server Management Studio!
Erik Hart

2
คำสั่ง IN เทียบเท่ากับ OR ใช้กับรายการพารามิเตอร์ / ค่า แต่ไม่ใช้กับการสืบค้นย่อยซึ่งส่วนใหญ่ถือว่าเหมือนกับการรวม
Erik Hart

42

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

ฉันมีตารางที่มี 50000 องค์ประกอบผลลัพธ์ที่ฉันมองหาคือ 739 องค์ประกอบ

คำถามของฉันในตอนแรกคือ:

SELECT  p.id,
    p.fixedId,
    p.azienda_id,
    p.categoria_id,
    p.linea,
    p.tipo,
    p.nome
FROM prodotto p
WHERE p.azienda_id = 2699 AND p.anno = (
    SELECT MAX(p2.anno) 
    FROM prodotto p2 
    WHERE p2.fixedId = p.fixedId 
)

และใช้เวลา 7.9 วินาทีในการดำเนินการ

คำถามของฉันในที่สุดคือ:

SELECT  p.id,
    p.fixedId,
    p.azienda_id,
    p.categoria_id,
    p.linea,
    p.tipo,
    p.nome
FROM prodotto p
WHERE p.azienda_id = 2699 AND (p.fixedId, p.anno) IN
(
    SELECT p2.fixedId, MAX(p2.anno)
    FROM prodotto p2
    WHERE p.azienda_id = p2.azienda_id
    GROUP BY p2.fixedId
)

และใช้เวลา 0.0256 วินาที

SQL ดีดี


3
น่าสนใจช่วยอธิบายได้ไหมว่าการเพิ่ม GROUP BY แก้ไขได้อย่างไร
cozos

6
ตารางชั่วคราวที่สร้างโดยแบบสอบถามย่อยมีขนาดเล็กกว่า ดังนั้นการดำเนินการจึงรวดเร็วกว่าเนื่องจากมีข้อมูลให้เช็คอินน้อยกว่า
Sirmyself

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

1
เซิร์ฟเวอร์ Sql และ MySql และ ... Sql (ยกเว้น NoSql) มีความคล้ายคลึงกันในโครงสร้างพื้นฐาน เรามีเครื่องมือเพิ่มประสิทธิภาพการค้นหาชนิดหนึ่งที่อยู่ด้านล่างซึ่งจะแปลงส่วนคำสั่ง IN (... ) เพื่อเข้าร่วม (ถ้าเป็นไปได้) แต่เมื่อคุณมี Group by ในคอลัมน์ที่มีการจัดทำดัชนีอย่างดี (ขึ้นอยู่กับจำนวนสมาชิก) มันจะเร็วขึ้นมาก ดังนั้นมันขึ้นอยู่กับสถานการณ์จริงๆ
Alix

10

เริ่มต้นดูแผนการดำเนินการเพื่อดูความแตกต่างว่าเซิร์ฟเวอร์ SQl จะตีความอย่างไร คุณยังสามารถใช้ Profiler เพื่อเรียกใช้แบบสอบถามได้หลายครั้งและได้รับความแตกต่าง

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

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


9

ประสิทธิภาพขึ้นอยู่กับจำนวนข้อมูลที่คุณกำลังดำเนินการ ...

ถ้าเป็นข้อมูลน้อยประมาณ 20k. JOIN ทำงานได้ดีขึ้น

หากข้อมูลมีค่ามากกว่า 100k + ดังนั้น IN จะทำงานได้ดีขึ้น

หากคุณไม่ต้องการข้อมูลจากตารางอื่น IN ก็ดี แต่การไป EXISTS จะดีกว่า

เกณฑ์ทั้งหมดที่ฉันทดสอบและตารางมีดัชนีที่เหมาะสม


4

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

(แก้ไขเพื่อให้สอดคล้องกับคำถามที่อัปเดต)


4

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

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


4

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

ฉันจะให้น้ำหนักกับข้อสังเกตต่อไปนี้ด้วย ฉันมีระเบียนประมาณ 45 ล้านรายการในตารางของฉัน ([ข้อมูล]) และประมาณ 300 รายการในตาราง [แมว] ของฉัน ฉันมีการจัดทำดัชนีที่ครอบคลุมสำหรับคำถามทั้งหมดที่ฉันกำลังจะพูดถึง

พิจารณาตัวอย่างที่ 1:

UPDATE d set category = c.categoryname
FROM [data] d
JOIN [cats] c on c.id = d.catid

เทียบกับตัวอย่างที่ 2:

UPDATE d set category = (SELECT TOP(1) c.categoryname FROM [cats] c where c.id = d.catid)
FROM [data] d

ตัวอย่างที่ 1 ใช้เวลาประมาณ 23 นาทีในการรัน ตัวอย่างที่ 2 ใช้เวลาประมาณ 5 นาที

ดังนั้นฉันจะสรุปว่าแบบสอบถามย่อยในกรณีนี้เร็วกว่ามาก แน่นอนว่าฉันใช้ไดรฟ์ M.2 SSD ที่มีความสามารถ i / o @ 1GB / วินาที (นั่นคือไบต์ไม่ใช่บิต) ดังนั้นดัชนีของฉันก็เร็วเช่นกัน ดังนั้นสิ่งนี้อาจส่งผลต่อความเร็วเช่นกันในสถานการณ์ของคุณ

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

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


0

คุณสามารถใช้แผนการอธิบายเพื่อรับคำตอบตามวัตถุประสงค์

สำหรับปัญหาของคุณตัวกรอง Existsน่าจะทำงานได้เร็วที่สุด


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

มันจะทำงานช้าลงในสถานการณ์สุดท้ายนั้นหรือไม่?
Snekse

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