ความแตกต่างระหว่าง EXISTS และ IN ใน SQL?


443

ความแตกต่างระหว่างEXISTSและINข้อใน SQL คืออะไร?

เราควรใช้EXISTSเมื่อใดและควรใช้เมื่อINใด

คำตอบ:


224

existsคำหลักที่สามารถนำมาใช้ในทางที่ แต่จริงๆก็ตั้งใจจะให้เป็นวิธีที่จะหลีกเลี่ยงการนับ:

--this statement needs to check the entire table
select count(*) from [table] where ...

--this statement is true as soon as one match is found
exists ( select * from [table] where ... )

สิ่งนี้มีประโยชน์มากที่สุดเมื่อคุณมีifคำสั่งแบบมีเงื่อนไขซึ่งexistsอาจเร็วกว่าcountมาก

inจะใช้ดีที่สุดที่คุณมีรายการคงผ่าน:

 select * from [table]
 where [field] in (1, 2, 3)

เมื่อคุณมีตารางในinคำสั่งมันเหมาะสมกว่าที่จะใช้ a joinแต่ส่วนใหญ่มันไม่สำคัญ เครื่องมือเพิ่มประสิทธิภาพการสืบค้นควรส่งคืนแผนเดียวกันด้วยวิธีใดวิธีหนึ่ง ในการใช้งานบางอย่าง (ส่วนใหญ่เก่ากว่าเช่น Microsoft SQL Server 2000) inแบบสอบถามจะได้รับแผนการเข้าร่วมที่ซ้อนกันเสมอในขณะที่joinแบบสอบถามจะใช้ซ้อนกันผสานหรือแฮตามความเหมาะสม การใช้งานที่ทันสมัยกว่ามีความชาญฉลาดและสามารถปรับแผนได้แม้ในขณะที่inใช้งาน


2
คุณสามารถอธิบายรายละเอียดเกี่ยวกับ "เมื่อคุณมีตารางในคำสั่ง in มันเหมาะสมกว่าที่จะใช้การเข้าร่วม แต่ไม่สำคัญจริงๆตัวเพิ่มประสิทธิภาพการสืบค้นจะส่งคืนแผนเดียวกันด้วยวิธีใด" ไม่ได้เป็นส่วนแบบสอบถามเพิ่มประสิทธิภาพ, ส่วนหนึ่งที่คุณสามารถใช้แทนสำหรับJOIN IN
farthVader

select * from [table] where [field] in (select [field] from [table2])ผลตอบแทนที่ได้ผลเหมือนกัน (และแผนแบบสอบถาม) select * from [table] join [table2] on [table2].[field] = [table].[field]เช่น

@Sander มันจะไม่แบบสอบถามแรกผลตอบแทนคอลัมน์ทั้งหมดจากtableในขณะที่ผลตอบแทนทุกอย่างที่สองจากและtable table2ในฐานข้อมูล SQL (เก่ากว่าส่วนใหญ่) inแบบสอบถามจะถูกนำไปใช้เป็นการเข้าร่วมที่ซ้อนกันในขณะที่joinแบบสอบถามสามารถซ้อนซ้อนผสานถูกแฮชและอื่น ๆ ได้เร็วที่สุด
Keith

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

existsสามารถนำมาใช้ในคำสั่งกรณีดังนั้นพวกเขาจึงมีประโยชน์เช่นนั้นด้วยselect case when exists (select 1 from emp where salary > 1000) then 1 else 0 end as sal_over_1000
smooth_smoothie

125

EXISTSจะบอกคุณว่าแบบสอบถามส่งคืนผลลัพธ์ใด ๆ หรือไม่ เช่น:

SELECT * 
FROM Orders o 
WHERE EXISTS (
    SELECT * 
    FROM Products p 
    WHERE p.ProductNumber = o.ProductNumber)

IN ใช้เพื่อเปรียบเทียบหนึ่งค่ากับหลาย ๆ และสามารถใช้ค่าตามตัวอักษรเช่นนี้:

SELECT * 
FROM Orders 
WHERE ProductNumber IN (1, 10, 100)

นอกจากนี้คุณยังสามารถใช้ผลการสืบค้นด้วยส่วนINคำสั่งเช่นนี้:

SELECT * 
FROM Orders 
WHERE ProductNumber IN (
    SELECT ProductNumber 
    FROM Products 
    WHERE ProductInventoryQuantity > 0)

3
ข้อความค้นหาสุดท้ายเป็นอันตรายเพราะอาจล้มเหลวในข้อความค้นหาย่อยจะไม่แสดงผลลัพธ์ใด ๆ ข้อ 'ใน' ต้องมีอย่างน้อย 1 อาร์กิวเมนต์ ...
user2054927

40
@ user2054927 การค้นหาล่าสุดจะไม่ส่งคืนแถวอย่างถูกต้องหากแบบสอบถามย่อยไม่ส่งคืนแถว - ไม่มีอันตรายใด ๆ !
Tony Andrews

คำตอบที่ดีที่สุด
Aminadav Glickshtein

81

ตามเครื่องมือเพิ่มประสิทธิภาพกฎ :

  • EXISTSเร็วกว่าINเมื่อผลลัพธ์ของแบบสอบถามย่อยมีขนาดใหญ่มาก
  • INเร็วกว่าEXISTSเมื่อผลลัพธ์แบบสอบถามย่อยมีขนาดเล็กมาก

ตามเครื่องมือเพิ่มประสิทธิภาพต้นทุน :

  • ไม่มีความแตกต่าง

21
พิสูจน์การโต้แย้งของคุณ? ฉันไม่คิดว่า IN จะเร็วกว่า EXISTS เลย!
Nawaz

22
@Nawaz วิธีการเกี่ยวกับหลักฐานว่าทำไมในช้ากว่า EXISTS เสมอ?
ceving

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

1
EXISTS ส่งคืนค่าบูลีนล้วนๆซึ่งเร็วกว่าการเปรียบเทียบสตริงหรือค่าที่มีขนาดใหญ่กว่าประเภท BIT / บูลีนเสมอ IN อาจจะใช่หรือไม่ใช่เป็นการเปรียบเทียบแบบบูลก็ได้ เนื่องจากโปรแกรมชอบการใช้งาน EXPLICIT เพื่อความเสถียร (ส่วนหนึ่งของกรด), EXISTS จึงเป็นที่ต้องการโดยทั่วไป
clifton_h

2
ทำไมสิ่งนี้จึงถูกโหวตขึ้นหลายครั้ง? ไม่มีเหตุผลใดที่เหตุผลที่ข้อความตามสมมติฐานนี้ควรเป็นจริง
Lukas Eder

40

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

นั่นคือสมมติฐานที่ยุติธรรมหรือไม่?


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

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

SELECT *
FROM Customers
WHERE EXISTS (
    SELECT *
    FROM Orders
    WHERE Orders.CustomerID = Customers.ID
)

สามารถเขียนใหม่เป็น:

SELECT *
FROM Customers
WHERE ID IN (
    SELECT CustomerID
    FROM Orders
)

หรือด้วยการเข้าร่วม:

SELECT Customers.*
FROM Customers
    INNER JOIN Orders ON Customers.ID = Orders.CustomerID

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


12
ฉันไม่รู้เกี่ยวกับ OP แต่ฉันต้องการคำตอบสำหรับคำถามนี้! เมื่อใดที่ฉันควรใช้ EXISTS แทนที่จะเป็น IN พร้อมกับแบบสอบถามย่อยที่ส่งคืน ID
Roy Tinker

8
ในJOINนั้นคุณจะต้องมีDISTINCT
Jaider

4
การสาธิตที่ดี แต่สวยมากออกจากคำถามที่ยังไม่ได้ตอบ
Junchen หลิว

28
  1. EXISTSเร็วกว่าINเมื่อผลลัพธ์ของแบบสอบถามย่อยมีขนาดใหญ่มาก
    INจะเร็วกว่าEXISTSเมื่อผลลัพธ์แบบสอบถามย่อยมีขนาดเล็กมาก

    CREATE TABLE t1 (id INT, title VARCHAR(20), someIntCol INT)
    GO
    CREATE TABLE t2 (id INT, t1Id INT, someData VARCHAR(20))
    GO
    
    INSERT INTO t1
    SELECT 1, 'title 1', 5 UNION ALL
    SELECT 2, 'title 2', 5 UNION ALL
    SELECT 3, 'title 3', 5 UNION ALL
    SELECT 4, 'title 4', 5 UNION ALL
    SELECT null, 'title 5', 5 UNION ALL
    SELECT null, 'title 6', 5
    
    INSERT INTO t2
    SELECT 1, 1, 'data 1' UNION ALL
    SELECT 2, 1, 'data 2' UNION ALL
    SELECT 3, 2, 'data 3' UNION ALL
    SELECT 4, 3, 'data 4' UNION ALL
    SELECT 5, 3, 'data 5' UNION ALL
    SELECT 6, 3, 'data 6' UNION ALL
    SELECT 7, 4, 'data 7' UNION ALL
    SELECT 8, null, 'data 8' UNION ALL
    SELECT 9, 6, 'data 9' UNION ALL
    SELECT 10, 6, 'data 10' UNION ALL
    SELECT 11, 8, 'data 11'
  2. แบบสอบถาม 1

    SELECT
    FROM    t1 
    WHERE   not  EXISTS (SELECT * FROM t2 WHERE t1.id = t2.t1id)

    แบบสอบถาม 2

    SELECT t1.* 
    FROM   t1 
    WHERE  t1.id not in (SELECT  t2.t1id FROM t2 )

    ถ้าในt1id ของคุณมีค่า Null แล้ว Query 1 จะค้นหาพวกมัน แต่ Query 2 ไม่สามารถหาพารามิเตอร์ที่เป็น null ได้

    ฉันหมายถึงINไม่สามารถเปรียบเทียบอะไรกับ null ได้ดังนั้นมันจึงไม่มีผลลัพธ์สำหรับ null แต่EXISTSสามารถเปรียบเทียบทุกอย่างกับ null ได้


คำตอบนี้เป็นบทสรุปที่สมเหตุสมผลของความเชื่อมั่นของ Tom Kite ( asktom.oracle.com/pls/asktom/ … )
Jeromy French

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

เคียวรี 2 เหล่านี้จะเทียบเท่ากันในเชิงตรรกะหากกำหนด t2.id เป็น "NOT NULL" เท่านั้น เมื่อต้องการให้สิทธิ์เทียบเท่าโดยไม่มีการอ้างอิงในคำจำกัดความของตารางแบบสอบถามที่ 2 ควรเป็น "SELECT t1. * จาก t1 WHERE t1.id ไม่ได้อยู่ใน (เลือก t2.id จาก T2 โดยที่ t2.id ไม่ใช่ null )"
David דודו Markovitz

16

หากคุณกำลังใช้INโอเปอเรเตอร์เครื่องยนต์ SQL จะสแกนเรคคอร์ดทั้งหมดที่ดึงมาจากเคียวรีด้านใน ในทางกลับกันถ้าเราใช้EXISTSเครื่องมือ SQL จะหยุดกระบวนการสแกนทันทีที่พบการจับคู่


10

INสนับสนุนความสัมพันธ์ที่เท่าเทียมกันเท่านั้น (หรือความไม่เท่าเทียมกันเมื่อนำหน้าด้วยNOT )
มันเป็นคำพ้องที่จะ= ใด ๆ / = บางอย่างเช่น

select    * 
from      t1 
where     x in (select x from t2)
;

EXISTSรองรับประเภทของความสัมพันธ์ที่หลากหลายซึ่งไม่สามารถแสดงได้โดยใช้INเช่น -

select    * 
from      t1 
where     exists (select    null 
                  from      t2 
                  where     t2.x=t1.x 
                        and t2.y>t1.y 
                        and t2.z like '℅' || t1.z || '℅'
                  )
;

และในบันทึกอื่น -

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

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


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

9

Existsคำหลักประเมินจริงหรือเท็จ แต่INคำหลักเปรียบเทียบค่าทั้งหมดในคอลัมน์แบบสอบถามย่อยที่สอดคล้องกัน อีกอันหนึ่งSelect 1สามารถใช้กับExistsคำสั่ง ตัวอย่าง:

SELECT * FROM Temp1 where exists(select 1 from Temp2 where conditions...)

แต่ INมีประสิทธิภาพน้อยลงExistsเร็วขึ้น


5

ฉันคิด,

  • EXISTSคือเมื่อคุณต้องการจับคู่ผลลัพธ์ของแบบสอบถามกับแบบสอบถามย่อยอื่น คำค้นหา # 1 จำเป็นต้องดึงข้อมูลที่ตรงกับผลลัพธ์ของแบบสอบถามย่อย ชนิดของการเข้าร่วม .. เช่นเลือกลูกค้าตาราง # 1 ที่ได้วางตารางคำสั่งซื้อ # 2 ด้วย

  • IN คือการดึงข้อมูลหากค่าของคอลัมน์ที่ระบุนั้นอยู่INในรายการ (1,2,3,4,5) เช่นเลือกลูกค้าที่อยู่ในรหัสไปรษณีย์ต่อไปนี้เช่นค่า zip_code อยู่ในรายการ (.... )

เมื่อใดควรใช้อีกตัวหนึ่ง ... เมื่อคุณรู้สึกว่าอ่านได้อย่างเหมาะสม (สื่อสารด้วยเจตนาที่ดีกว่า)


4

ความแตกต่างอยู่ที่นี่:

select * 
from abcTable
where exists (select null)

แบบสอบถามด้านบนจะส่งคืนระเบียนทั้งหมดในขณะที่รายการด้านล่างจะส่งคืนค่าว่าง

select *
from abcTable
where abcTable_ID in (select null)

ลองดูและสังเกตผลลัพธ์


1
อืม ... ข้อผิดพลาด: [SQL0104] โทเค็น) ไม่ถูกต้อง ในทั้งสองกรณี. คุณคิดว่า RDBMS เป็นพิเศษหรือไม่?
jmarkmurphy

3

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


3

อันที่เร็วกว่านั้นขึ้นอยู่กับจำนวนการสืบค้นที่สืบค้นโดยการสืบค้นภายใน:

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

มีอยู่ประเมินบนจริงหรือเท็จ แต่ในการเปรียบเทียบค่าหลายค่า เมื่อคุณไม่ทราบว่ามีระเบียนอยู่หรือไม่คุณควรเลือกมีอยู่


3

เหตุผลก็คือผู้ประกอบการ EXISTS ทำงานตามหลักการ“ อย่างน้อยพบ” มันจะคืนค่าจริงและหยุดสแกนตารางหนึ่งครั้งอย่างน้อยหนึ่งแถวที่พบ

ในทางกลับกันเมื่อตัวดำเนินการ IN รวมกับแบบสอบถามย่อย MySQL จะต้องประมวลผลแบบสอบถามย่อยก่อนแล้วจึงใช้ผลลัพธ์ของแบบสอบถามย่อยเพื่อประมวลผลแบบสอบถามทั้งหมด

กฎทั่วไปของหัวแม่มือคือถ้าแบบสอบถามย่อยมีข้อมูลจำนวนมากผู้ประกอบการ EXISTS จะให้ประสิทธิภาพที่ดีกว่า

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


1

ความเข้าใจของฉันคือทั้งคู่ควรจะเหมือนกันตราบใดที่เราไม่ได้เกี่ยวข้องกับค่า NULL

เหตุผลเดียวกันกับที่เคียวรีไม่ส่งคืนค่าสำหรับ = NULL vs คือ NULL http://sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in/

ในฐานะที่เป็นอาร์กิวเมนต์บูลีน vs comparator ไปเพื่อสร้างบูลีนทั้งสองค่าจะต้องมีการเปรียบเทียบและนั่นคือวิธีการใด ๆ ถ้าเงื่อนไขใช้งานได้ดังนั้นฉันล้มเหลวที่จะเข้าใจว่า IN และ EXISTS ทำงานอย่างไรแตกต่างกัน



0

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

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


0

ฉันเชื่อว่านี่เป็นคำตอบที่ตรงไปตรงมา ทำไมคุณไม่ตรวจสอบจากคนที่พัฒนาฟังก์ชั่นนั้นในระบบของพวกเขา?

หากคุณเป็นนักพัฒนา MS SQL นี่คือคำตอบโดยตรงจาก Microsoft

IN:

กำหนดว่าค่าที่ระบุตรงกับค่าใด ๆ ในแบบสอบถามย่อยหรือรายการ

EXISTS:

ระบุเคียวรีย่อยเพื่อทดสอบการมีอยู่ของแถว


0

ฉันพบว่าการใช้คำหลัก EXISTS มักจะช้ามาก (นั่นเป็นเรื่องจริงใน Microsoft Access) ฉันแทนที่จะใช้โอเปอเรเตอร์การรวมในลักษณะนี้: should-i-use-the-keyword-exist-in-sql


-1

EXISTS ทำงานได้เร็วขึ้นกว่าใน หากเกณฑ์ตัวกรองส่วนใหญ่อยู่ในแบบสอบถามย่อยควรใช้ IN และดีกว่าหากเกณฑ์ตัวกรองส่วนใหญ่อยู่ในแบบสอบถามหลักให้ใช้ EXISTS ได้ดีกว่า


การอ้างสิทธิ์นั้นไม่ได้รับการสนับสนุนจากหลักฐานใด ๆ จริงหรือ
Lukas Eder

-2

หากคุณใช้ตัวดำเนินการ IN โปรแกรม SQL จะสแกนระเบียนทั้งหมดที่ดึงมาจากแบบสอบถามภายใน ในทางตรงกันข้ามถ้าเราใช้ EXISTS เอ็นจิน SQL จะหยุดกระบวนการสแกนทันทีที่พบการจับคู่


@ziggy อธิบายหรือไม่ นี่เป็นคำตอบที่ได้รับการยอมรับ ในต้องตรวจสอบทุก ๆ ระเบียนที่มีอยู่สามารถหยุดได้ทันทีที่พบเพียงหนึ่งรายการ
Ben Thurley

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