SQL IN () contro OR

21

Stavo lavorando con una query che ho scritto oggi dovevo cambiare il codice dalla clausola WHERE per usare un filtro IN (lista 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 è durato per 15 minuti e non ha restituito nulla, tuttavia quanto segue mi ha dato il mio risultato impostato in 1,5 minuti

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

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

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

Ecco la query nella sua interezza utilizzando le istruzioni 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

Grazie,

    
posta MCP_infiltrator 12.07.2013 - 00:34
fonte

2 risposte

29

La risposta di Oleski è errata. Per SQL Server 2008, un elenco IN viene rifatto a una serie di istruzioni OR . Potrebbe essere diverso per esempio MySQL.

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

Con tutta probabilità la seconda query è stata più veloce perché è stata eseguita secondo e la prima query ha già richiamato tutte le pagine di dati dal database e pagato il costo dell'IO. La seconda query è stata in grado di leggere tutti i dati dalla memoria ed eseguirli molto più velocemente.

Aggiorna

La fonte effettiva della varianza è probabile che le query siano non equivalenti . Di seguito sono elencati due diversi elenchi di 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'

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 le clausole WHERE , la precondenza dell'operatore (dove AND viene gestito prima di OR) indica che la logica effettiva eseguita dal motore è:

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

Se sostituisci gli elenchi OR con un'espressione IN , la logica sarà:

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

Che è radicalmente diverso.

    
risposta data 12.07.2013 - 14:08
fonte
7

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

Detto questo, i sistemi DBMS sono veramente bravi a fare operazioni tra due tabelle (come i join). Gran parte del tempo di ottimizzazione viene speso per queste parti delle query perché sono generalmente più costose.

Ad esempio, il DBMS potrebbe ordinare l'elenco IN e, utilizzando un indice su item_desc , filtrare i risultati molto rapidamente. Non è possibile eseguire questa ottimizzazione quando si elencano alcune selezioni come nel primo esempio.

Quando utilizzi IN , stai creando una tabella e un filtro estemporanei usando queste tecniche di combinazione di tabelle più efficienti.

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

    
risposta data 12.07.2013 - 01:36
fonte

Leggi altre domande sui tag