Domanda

Stavo lavorando con una query che ho scritto oggi doveva modificare il codice dalla clausola WHERE per utilizzare un filtro in (elenco di cose di roba) 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 correva per 15 minuti e non ha restituito nulla, tuttavia il seguente 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 chiedo perché il pollice in (elenco di articoli) ha eseguito così tanto più velocemente dell'istruzione o della dichiarazione.

- Modifica - SQL Server 2008, mi scuso per non mettere 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,

È stato utile?

Soluzione

La risposta di Oleski non è corretta. Per SQL Server 2008, un elenco IN viene refalato a una serie di dichiarazioni OR. Potrebbe essere diverso in dire MySQL.

Sono abbastanza certo che se hai generato piani di esecuzione effettivi per entrambe le domande che sarebbero identiche.

In tutta la probabilità che la seconda query correva più veloce perché la correggi secondo e la prima query aveva già tirato tutte le pagine dei dati dal database e ha pagato il costo IO. La seconda query è stata in grado di leggere tutti i dati dalla memoria ed eseguire molto più velocemente.

Aggiornamento

La sorgente effettiva della varianza è probabile che le query siano non equivalenti . Hai due diversi elenchi OR di seguito:

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 successivi

 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 precentra dell'operatore (dove ed è gestita prima o) significa che la logica effettiva da parte del motore è:

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

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

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

che è radicalmente diverso.

Altri suggerimenti

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

Con ciò detto, i sistemi DBMS sono davvero bravi a fare operazioni tra due tavoli (come joins). Un sacco di tempo del tempo dell'ottimizzatore viene speso su queste parti delle query perché sono generalmente più costose.

Ad esempio, il DBMS potrebbe ordinare quell'elenco IN e, utilizzando un indice su item_desc, filtrare i risultati molto rapidamente. Non puoi fare questa ottimizzazione quando elenchi un sacco di selezioni come nel primo esempio.

Quando si utilizza IN, stai facendo una tabella improvvisata e il filtraggio utilizzando queste tecniche di combinazione di tabelle più efficienti.

Modifica : Ho pubblicato questa risposta prima dell'OP menzionato il DBM specifico. Ciò 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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
scroll top