ความแตกต่างระหว่าง NOT EXISTS กับ NOT IN และ LEFT JOIN จะอยู่ที่ไหน NULL?


151

ฉันว่าคุณสามารถทำสิ่งเดียวกันในแบบสอบถาม SQL โดยใช้ไม่อยู่ไม่เข้าหรือซ้ายเข้าร่วมซึ่งเป็นโมฆะ ตัวอย่างเช่น:

SELECT a FROM table1 WHERE a NOT IN (SELECT a FROM table2)

SELECT a FROM table1 WHERE NOT EXISTS (SELECT * FROM table2 WHERE table1.a = table2.a)

SELECT a FROM table1 LEFT JOIN table2 ON table1.a = table2.a WHERE table1.a IS NULL

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


6
เอ็นจิน SQL ทั่วไปจำนวนมากให้ความสามารถในการดูแผนการดำเนินการ คุณมักจะเห็นความแตกต่างอย่างมีนัยสำคัญในประสิทธิภาพสำหรับคำค้นหาที่มีเหตุผลในลักษณะนี้ ความสำเร็จของวิธีการใด ๆ ขึ้นอยู่กับปัจจัยต่าง ๆ เช่นขนาดของตารางดัชนีใดบ้างที่มีอยู่และอื่น ๆ
Chris Farmer

2
@ วิช: ไม่มีฐานข้อมูลที่สนใจว่าคุณกลับมาอยู่ตรงไหนในEXISTSประโยค คุณอาจจะกลับมา*, NULLหรืออะไรก็ตาม: ทั้งหมดนี้จะถูกปรับออกไป
Quassnoi

2
@wich - ทำไม ทั้งที่นี่: techonthenet.com/sql/exists.phpและที่นี่: msdn.microsoft.com/en-us/library/ms188336.aspxดูเหมือนจะใช้ * ...
Froadie

8
@ วิช: มันไม่เกี่ยวกับ "การแสดงความสนใจ" นี้เป็นเรื่องเกี่ยวกับตัวแยกวิเคราะห์แบบสอบถามเรียกร้องให้คุณใส่อะไรบางอย่างระหว่างและSELECT FROMและ*พิมพ์ง่ายกว่า ใช่SQLมีความคล้ายคลึงกับภาษาธรรมชาติ แต่มีการแยกวิเคราะห์และดำเนินการโดยเครื่องซึ่งเป็นเครื่องที่ตั้งโปรแกรมไว้ ไม่ใช่ว่ามันจะบุกเข้ามาในห้องเล็ก ๆ ของคุณและตะโกนว่า "หยุดเรียกร้องให้มีการเพิ่มเขตข้อมูลในEXISTSแบบสอบถามเพราะฉันรู้สึกไม่สบายใจที่จะแยกพวกเขาแล้วโยนมันทิ้ง!" ไม่เป็นไรกับคอมพิวเตอร์จริงๆ
Quassnoi

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

คำตอบ:


139

โดยสังเขป:

NOT INแตกต่างกันเล็กน้อย: มันไม่ตรงกันถ้ามี แต่รายการเดียวNULLในรายการ

  • ในMySQL, NOT EXISTSมีประสิทธิภาพนิด ๆ หน่อย ๆ น้อย

  • ในSQL Server, LEFT JOIN / IS NULLมีประสิทธิภาพน้อย

  • ในPostgreSQL, NOT INมีประสิทธิภาพน้อย

  • ในOracleทั้งสามวิธีเหมือนกัน


1
ขอบคุณสำหรับลิงค์! และขอขอบคุณสำหรับภาพรวมอย่างรวดเร็ว ... ที่ทำงานของฉันบล็อกการเชื่อมโยงด้วยเหตุผลบางอย่าง: P แต่ฉันจะตรวจสอบมันทันทีที่ฉันไปถึงคอมพิวเตอร์ทั่วไป
froadie

2
ประเด็นก็คือว่าถ้าtable1 .aมีแบบสอบถามจะไม่กลับมาแถวนี้ แต่แบบสอบถามจะถ้าเป็นที่ว่างเปล่า ไม่ได้อยู่ในและไม่มีอยู่คอลัมน์ที่เป็นโมฆะ: SQL ServerNULLEXISTSNOT INtable2
Martin Smith

@MartinSmith: NULL NOT IN ()ประเมินเป็นจริง (ไม่ใช่NULL) เช่นเดียวกับNOT EXISTS (NULL = column)
Quassnoi

2
@Quassnoi - เอ้อจุดดีได้วิธีผิดรอบ NOT EXISTSมักจะกลับแถว แต่NOT INจะทำเช่นนั้นถ้าแบบสอบถามย่อยส่งกลับไม่มีแถว
Martin Smith

5

หากฐานข้อมูลดีในการปรับการสืบค้นทั้งสองให้ดีก่อนจะถูกแปลงเป็นสิ่งที่ใกล้เคียงกับที่สาม

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


2

สมมติว่าคุณกำลังหลีกเลี่ยงค่า Null แต่เป็นวิธีการต่อต้านการเข้าร่วมโดยใช้ Standard SQL

การละเลยที่ชัดเจนนั้นเทียบเท่ากับการใช้EXCEPT:

SELECT a FROM table1
EXCEPT
SELECT a FROM table2

หมายเหตุใน Oracle คุณต้องใช้MINUSโอเปอเรเตอร์ (ชื่อที่ดีกว่า):

SELECT a FROM table1
MINUS
SELECT a FROM table2

เมื่อพูดถึงไวยากรณ์ที่เป็นกรรมสิทธิ์อาจมีการตรวจสอบที่เทียบเท่าแบบไม่ได้มาตรฐานซึ่งขึ้นอยู่กับผลิตภัณฑ์ที่คุณใช้เช่นOUTER APPLYใน SQL Server (เช่น):

SELECT t1.a
  FROM table1 t1
       OUTER APPLY 
       (
        SELECT t2.a
          FROM table2 t2
         WHERE t2.a = t1.a
       ) AS dt1
 WHERE dt1.a IS NULL;

0

เมื่อต้องการแทรกข้อมูลในตารางด้วยคีย์หลักแบบหลายฟิลด์ให้พิจารณาว่าจะเร็วกว่ามาก (ฉันลองใช้ Access แต่ฉันคิดว่าในฐานข้อมูลใด ๆ ) ไม่ต้องตรวจสอบว่า "ไม่มีระเบียนอยู่ด้วยค่า 'เช่น' ในตาราง" - เพียงแค่แทรกลงในตารางและบันทึกส่วนเกิน (โดยคีย์) จะไม่ถูกแทรกสองครั้ง


0

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


1
และสิ่งที่คุณเสนอให้เป็นวิธีแก้ปัญหาเมื่อคุณต้องการNOT?
dnoeth

เมื่อไม่มีตัวเลือกของสาเหตุที่เราต้องใช้การดำเนินการไม่และนั่นคือเหตุผลที่พวกเขามีอยู่ แนวทางปฏิบัติที่ดีที่สุดคือหลีกเลี่ยงพวกเขาเมื่อเรามีทางเลือกอื่น
Lahiru Cooray

@onedaywhen หากเครื่องมือเพิ่มประสิทธิภาพเปลี่ยนการสืบค้นและส่งคืนผลลัพธ์ที่ผิดนั่นเป็นข้อผิดพลาด
David โดย Markovitz

@DuduMarkovitz: ใช่และถ้าคุณติดต่อทีม SQL Server และพวกเขารับทราบข้อผิดพลาด แต่ปฏิเสธที่จะแก้ไขได้เพราะพวกเขาบอกว่าการทำเช่นนั้นอาจจะทำให้คำสั่งทำงานช้าลงแล้วมันก็เป็นข้อผิดพลาดที่คุณต้องจัดการกับ
oneday เมื่อ

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