SQL IN () contro OR


23

Stavo lavorando con una query che ho scritto oggi ho dovuto cambiare il codice dalla WHEREclausola per usare un filtro IN (elenco di cose) invece di usare qualcosa come

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

Quanto sopra ha funzionato per 15 minuti e non ha restituito nulla, tuttavia quanto segue mi ha dato il mio set di risultati in 1,5 minuti

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

L'ho fatto in SQL e mi chiedo perché IN (elenco di elementi) abbia funzionato molto più velocemente dell'istruzione OR.

- EDIT - SQL Server 2008, mi scuso per non aver inserito questo bit di informazioni in primo luogo.

Ecco la Query nella sua interezza usando le ORistruzioni:

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

Grazie,


10
Hai esaminato il piano di query?

1
Questo è MOLTO specifico per l'implementazione. Quale DBMS stai usando?
James Anderson,

Non ho esaminato il piano di query, non sapevo se si trattasse di una query specifica o se fosse un dato di fatto, poiché in questo modo avrebbe sempre funzionato in questo modo.
MCP_infiltrator,

3
@MCP_infiltrator Quindi i piani di esecuzione non saranno equivalenti perché la logica non è equivalente. Quando si utilizza ORcome si fa nella query effettiva sopra, si consente il corto circuito del motore. WHERE A AND B OR Cvaluterà vero anche se A AND B sono falsi, se C è vero. Se dici WHERE A and B OR C OR D OR E OR Fcome fai sopra, AND puoi prendere in considerazione. La logica equivalente effettivo sarebbe incapsulare le ORserie di cui sopra in modo parentesi sono trattati come set: WHERE A AND (B OR C OR D OR E). Ecco come INviene trattato un.
JNK,

5
La precendenza dell'operatore in SQL Server ha specificato che ANDviene gestita in precedenza OR, quindi la query sopra è equivalente al 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'che significa che se una delle ultime 3 condizioni è vera, sarà in grado di cortocircuitare il resto della valutazione.
JNK,

Risposte:


28

La risposta di Oleski non è corretta. Per SQL Server 2008, un INelenco viene refactored in una serie di ORistruzioni. MySQL potrebbe essere diverso.

Sono abbastanza certo che se avessi generato piani di esecuzione effettivi per entrambe le tue domande sarebbero identici.

Con ogni probabilità la seconda query è stata eseguita più rapidamente perché è stata eseguita per seconda , e la prima query aveva già estratto tutte le pagine di dati dal database e pagato il costo di I / O. La seconda query è stata in grado di leggere tutti i dati dalla memoria ed eseguire molto più velocemente.

Aggiornare

La fonte effettiva della varianza è probabile che le query non siano equivalenti . Di seguito sono riportati due ORelenchi diversi :

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'

e più tardi

 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'

In entrambe queste WHEREclausole, la precendenza dell'operatore (dove AND viene gestito prima di OR) significa che la logica effettiva gestita dal motore è:

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

Se si sostituiscono gli ORelenchi con INun'espressione, la logica sarà:

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

Che è radicalmente diverso.


2
@MCP_infiltrator Bene, questo è il problema con le assunzioni :) Dovresti davvero ottenere piani esecutivi effettivi per entrambi e vedere se c'è una differenza, non penso che ci sarà.
JNK,

4
Bene, se hai una domanda DB avanzata, puoi anche chiedere agli amministratori del database : divulgazione completa, sono un moderatore laggiù, ma se si tratta di una domanda avanzata di ottimizzazione SQL o SQL abbiamo un sacco di esperti, specialmente per SQL Server
JNK

1
Ho appena esaminato i due piani di esecuzione e sono molto diversi. La query con le istruzioni OR occupa il 68% dei costi nella scansione dell'indice cluster, dove l'istruzione IN è del 26%, insieme a quelle che sembrano essere anche meno fasi di esecuzione.
MCP_infiltrator

3
@MCP_infiltrator Non c'è bisogno, vedi i miei commenti sul tuo post originale in alto. INnon equivale a ORquanto sopra riportato a causa delle altre condizioni della WHEREclausola nella query effettiva. Fondamentalmente le query restituiranno risultati diversi.
JNK,

3
@MCP_infiltrator Non è necessario pubblicare una domanda identica su DBA.SE, JNK ha risposto (e otterrai risposte simili lì.) Se vuoi spostarti ("migrare") lì, puoi sempre contrassegnarlo (la tua domanda) menzionando nella casella dei commenti ciò che desideri. Le mod si prenderanno cura di loro.
ypercubeᵀᴹ

7

Il modo migliore per dire è guardare il piano di query effettivo usando qualcosa di simile EXPLAIN. Questo dovrebbe dirti esattamente cosa sta facendo il DBMS e quindi puoi avere un'idea molto migliore del perché sia ​​più efficiente.

Detto questo, i sistemi DBMS sono davvero bravi a fare operazioni tra due tabelle (come i join). Molto tempo dell'ottimizzatore viene speso per queste parti delle query perché sono generalmente più costose.

Ad esempio, il DBMS potrebbe ordinare tale INelenco e, utilizzando un indice item_descattivo, filtrare i risultati molto rapidamente. Non è possibile eseguire tale ottimizzazione quando si elenca un gruppo di selezioni come nel primo esempio.

Quando si utilizza IN, si crea una tabella improvvisata e si filtra utilizzando queste tecniche di combinazione di tabelle più efficienti.

EDIT : ho pubblicato questa risposta prima che OP menzionasse il DBMS specifico. Questo risulta NON essere il modo in cui SQL Server tratta questa query, ma potrebbe essere valido per altri sistemi DBMS. Vedi la risposta di JNK per una risposta più specifica e accurata.


Immagino che la cardinalità abbia molto a che fare con questo. Non INsarebbe così veloce se fosse una sottoselezione con 100 registrazioni al suo interno, o un migliaio.
Robert Harvey,

@RobertHarvey Sì, probabilmente è vero, ma non mi aspetto neanche che sia molto peggio.
Oleksi,

Grazie @Oleksi Non sapevo che il DBMS avrebbe reso l'istruzione IN un elenco improvvisato
MCP_infiltrator

1
-1 - In SQL Server l' INistruzione non viene convertita in una tabella, viene trattata in modo identico in una serie di ORs.
JNK,

2
@ Katana314 Se EXPLAIN fosse una parola chiave in SQL Server (che utilizza l'OP) sarei d'accordo con te, ma non è così non è rilevante.
JNK,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.