SQL IN () กับ OR


23

ฉันทำงานกับแบบสอบถามที่ฉันเขียนวันนี้ต้องเปลี่ยนรหัสจากส่วนWHEREคำสั่งเพื่อใช้ตัวกรอง IN (รายการสิ่ง) แทนการใช้สิ่งที่ชอบ

item_desc = 'item 1'
OR item_desc = 'item 2'
OR item_desc = 'item 3'
OR item_desc = 'item 4'

ข้างต้นวิ่งเป็นเวลา 15 นาทีและไม่ได้คืนสิ่งใดเลย แต่สิ่งต่อไปนี้ให้ผลลัพธ์ของฉันใน 1.5 นาที

item_desc IN (
'item 1'
,'item 2'
,'item 3'
,'item 4'
)

ฉันทำสิ่งนี้ใน SQL และสงสัยว่าทำไม IN (รายการของรายการ) จึงทำงานได้เร็วกว่าคำสั่ง OR

- แก้ไข - SQL Server 2008 ฉันขอโทษที่ไม่ใส่ข้อมูลนี้ในตอนแรก

ต่อไปนี้เป็นข้อความค้นหาอย่างครบถ้วนโดยใช้ORข้อความ:

DECLARE @SD DATETIME
DECLARE @ED DATETIME
SET @SD = '2013-06-01';
SET @ED = '2013-06-15';

-- COLUMN SELECTION
SELECT PV.PtNo_Num AS 'VISIT ID'
, PV.Med_Rec_No AS 'MRN'
, PV.vst_start_dtime AS 'ADMIT'
, PV.vst_end_dtime AS 'DISC'
, PV.Days_Stay AS 'LOS'
, PV.pt_type AS 'PT TYPE'
, PV.hosp_svc AS 'HOSP SVC'
, SO.ord_no AS 'ORDER NUMBER'
--, SO.ent_dtime AS 'ORDER ENTRY TIME'
--, DATEDIFF(HOUR,PV.vst_start_dtime,SO.ent_dtime) AS 'ADM TO ENTRY HOURS'
, SO.svc_desc AS 'ORDER DESCRIPTION'
, OSM.ord_sts AS 'ORDER STATUS'
, SOS.prcs_dtime AS 'ORDER STATUS TIME'
, DATEDIFF(DAY,PV.vst_start_dtime,SOS.prcs_dtime) AS 'ADM TO ORD STS IN DAYS'

-- DB(S) USED
FROM smsdss.BMH_PLM_PtAcct_V PV
JOIN smsmir.sr_ord SO
ON PV.PtNo_Num = SO.episode_no
JOIN smsmir.sr_ord_sts_hist SOS
ON SO.ord_no = SOS.ord_no
JOIN smsmir.ord_sts_modf_mstr OSM
ON SOS.hist_sts = OSM.ord_sts_modf_cd

-- FILTER(S)
WHERE PV.Adm_Date BETWEEN @SD AND @ED
AND SO.svc_cd = 'PCO_REMFOLEY'
OR SO.svc_cd = 'PCO_INSRTFOLEY'
OR SO.svc_cd = 'PCO_INSTFOLEY'
OR SO.svc_cd = 'PCO_URIMETER'

AND SO.ord_no NOT IN (
    SELECT SO.ord_no
    FRROM smsdss.BMH_PLM_PtAcct_V PV
    JOIN smsmir.sr_ord SO
    ON PV.PtNo_Num = SO.episode_no
    JOIN smsmir.sr_ord_sts_hist SOS
    ON SO.ord_no = SOS.ord_no
    JOIN smsmir.ord_sts_modf_mstr OSM
    ON SOS.hist_sts = OSM.ord_sts_modf_cd
    WHERE OSM.ord_sts = 'DISCONTINUE'
    AND SO.svc_cd = 'PCO_REMFOLEY'
    OR SO.svc_cd = 'PCO_INSRTFOLEY'
    OR SO.svc_cd = 'PCO_INSTFOLEY'
    OR SO.svc_cd = 'PCO_URIMETER'
)
ORDER BY PV.PtNo_Num, SO.ord_no, SOS.prcs_dtime

ขอขอบคุณ,


10
คุณได้ดูแผนแบบสอบถามแล้วหรือยัง

1
นี่คือการใช้งานที่เฉพาะเจาะจงมาก คุณใช้ DBMS รุ่นใดอยู่
James Anderson

ฉันไม่ได้ดูแผนแบบสอบถามฉันไม่ทราบว่านี่เป็นแบบสอบถามเฉพาะหรือถ้ามันเป็นเรื่องของความเป็นจริงเช่นนี้มักจะทำงานในรูปแบบนี้
MCP_infiltrator

3
@MCP_infiltrator ดังนั้นแผนการดำเนินการจะไม่เท่ากันเนื่องจากตรรกะไม่เท่ากัน เมื่อใช้งานORเหมือนกับที่คุณทำในแบบสอบถามจริงด้านบนคุณอนุญาตให้เครื่องยนต์ลัดวงจร WHERE A AND B OR Cจะประเมินเป็นจริงแม้ว่า A และ B จะเป็นเท็จหาก C เป็นจริง หากคุณพูดWHERE A and B OR C OR D OR E OR Fเหมือนที่คุณทำข้างต้นAND สามารถแยกออกได้ ตรรกะเทียบเท่าที่เกิดขึ้นจริงจะแค็ปซูซีรีส์ดังกล่าวข้างต้นในวงเล็บเพื่อให้พวกเขาได้รับการปฏิบัติเป็นชุด:OR WHERE A AND (B OR C OR D OR E)นี่คือวิธีการINรักษา
JNK

5
การดำเนินการของผู้ประกอบการใน SQL Server ที่ระบุไว้ซึ่งANDได้รับการจัดการมาก่อนORดังนั้นการสืบค้นของคุณข้างต้นจึงเท่ากับWHERE (OSM.ord_sts = 'DISCONTINUE' AND SO.svc_cd = 'PCO_REMFOLEY') OR SO.svc_cd = 'PCO_INSRTFOLEY' OR SO.svc_cd = 'PCO_INSTFOLEY' OR SO.svc_cd = 'PCO_URIMETER'ซึ่งหมายความว่าหากเงื่อนไข 3 ข้อสุดท้ายเป็นจริงมันจะสามารถลัดวงจรการประเมินที่เหลือได้
JNK

คำตอบ:


28

คำตอบของ Oleski ไม่ถูกต้อง สำหรับ SQL Server 2008 INรายการจะได้รับ refactored เป็นชุดของORข้อความสั่ง มันอาจจะแตกต่างกันในการพูด MySQL

ฉันค่อนข้างแน่ใจว่าถ้าคุณสร้างแผนการดำเนินการตามจริงสำหรับทั้งคำถามของคุณพวกเขาจะเหมือนกัน

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

ปรับปรุง

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

WHERE PV.Adm_Date BETWEEN @SD AND @ED
AND SO.svc_cd = 'PCO_REMFOLEY'
OR SO.svc_cd = 'PCO_INSRTFOLEY'
OR SO.svc_cd = 'PCO_INSTFOLEY'
OR SO.svc_cd = 'PCO_URIMETER'

และหลังจากนั้น

 WHERE OSM.ord_sts = 'DISCONTINUE'
    AND SO.svc_cd = 'PCO_REMFOLEY'
    OR SO.svc_cd = 'PCO_INSRTFOLEY'
    OR SO.svc_cd = 'PCO_INSTFOLEY'
    OR SO.svc_cd = 'PCO_URIMETER'

ในทั้งสองส่วนWHEREคำสั่งของผู้ปฏิบัติงาน (ที่ AND ถูกจัดการก่อนหน้า OR) หมายความว่าตรรกะจริงที่รันโดยเอ็นจิ้นคือ:

WHERE (ConditionA AND ConditionB)
OR ConditionC
OR ConditionD
OR ConditionE

หากคุณแทนที่ORรายการด้วยการINแสดงออกตรรกะจะเป็น:

WHERE ConditionA
AND (ConditionB OR ConditionC OR ConditionD OR ConditionE)

ซึ่งแตกต่างอย่างสิ้นเชิง


2
@MCP_infiltrator นั่นเป็นปัญหาของการตั้งสมมติฐาน :) คุณควรได้รับแผนปฏิบัติการจริงสำหรับทั้งสองและดูว่ามีความแตกต่างฉันไม่คิดว่าจะมี
JNK

4
ถ้าคุณมีคำถาม DB ขั้นสูงคุณสามารถถามผู้ดูแลฐานข้อมูลได้ - การเปิดเผยแบบเต็มฉันเป็นผู้ดำเนินรายการ แต่ถ้าเป็นคำถาม SQL หรือ SQL Optimization ขั้นสูงเรามีผู้เชี่ยวชาญหลายคนโดยเฉพาะ SQL Server
JNK

1
ฉันแค่ดูที่แผนปฏิบัติการทั้งสองและพวกมันก็แตกต่างกัน แบบสอบถามที่มีคำสั่ง OR จะใช้ค่าใช้จ่าย 68% ในการสแกนดัชนีแบบกลุ่มซึ่งคำสั่ง IN คือ 26% พร้อมกับสิ่งที่ดูเหมือนว่าจะเป็นขั้นตอนการดำเนินการที่น้อยลงเช่นกัน
MCP_infiltrator

3
@MCP_infiltrator ไม่จำเป็นต้องดูความคิดเห็นของฉันในโพสต์ต้นฉบับของคุณที่ด้านบน INไม่เท่ากับของคุณORข้างต้นเนื่องจากเงื่อนไขอื่น ๆ ในWHEREข้อของคุณในแบบสอบถามจริง โดยทั่วไปแบบสอบถามจะส่งคืนผลลัพธ์ที่แตกต่าง
JNK

3
@MCP_infiltrator ไม่จำเป็นต้องโพสต์คำถามที่เหมือนกันที่ DBA.SE, JNK ได้ตอบแล้ว (และคุณจะได้รับคำตอบที่คล้ายกันที่นั่น) หากคุณต้องการย้าย ("โยกย้าย") ที่นั่นแม้ว่าคุณสามารถตั้งค่าสถานะได้เสมอ (คำถามของคุณ) พูดถึงในช่องแสดงความคิดเห็นในสิ่งที่คุณต้องการ mods จะดูแล
ypercubeᵀᴹ

7

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

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

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

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

แก้ไข : ฉันโพสต์คำตอบนี้ก่อน OP กล่าวถึง DBMS เฉพาะ สิ่งนี้กลายเป็นว่า SQL Server ปฏิบัติต่อแบบสอบถามนี้ไม่ได้ แต่อาจใช้ได้กับระบบ DBMS อื่น ๆ ดูคำตอบของ JNKสำหรับคำตอบที่เฉพาะเจาะจงและแม่นยำมากขึ้น


ฉันคิดว่า cardinality มีส่วนเกี่ยวข้องกับเรื่องนี้มาก นั่นINจะไม่เร็วนักถ้ามันเป็นตัวเลือกย่อยที่มี 100 รายการในนั้นหรือหนึ่งพัน
Robert Harvey

@ RobertHarvey ใช่มันอาจเป็นจริง แต่ฉันไม่คิดว่ามันจะแย่ไปกว่านั้น
Oleksi

ขอบคุณ @Oleksi ฉันไม่ทราบว่า DBMS จะทำให้คำสั่ง IN เป็นรายการทันควัน
MCP_infiltrator

1
-1 - ใน SQL Server INคำสั่งไม่ถูกแปลงเป็นตารางจะถือว่าเป็นชุดของORs
JNK

2
@ Katana314 หากคำอธิบายเป็นคำสำคัญใน SQL Server (ซึ่ง OP ใช้) ฉันจะเห็นด้วยกับคุณ แต่ก็ไม่เป็นเช่นนั้น
JNK
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.