Question

Je travaillais avec une requête que j'ai écrite aujourd'hui et j'ai dû changer le code du WHERE clause pour utiliser un filtre IN(list of stuff) au lieu d'utiliser quelque chose comme

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

Ce qui précède a duré 15 minutes et n'a rien renvoyé, mais ce qui suit m'a donné mon résultat défini en 1,5 minute

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

J'ai fait cela en SQL et je me demande pourquoi l'IN (liste d'éléments) a fonctionné beaucoup plus rapidement que l'instruction OR.

- Edit - SQL Server 2008, je m'excuse de ne pas avoir mis ce peu d'informations en premier lieu.

Voici la requête dans son intégralité en utilisant le OR déclarations:

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

Merci,

Était-ce utile?

La solution

La réponse d'Oleski est incorrecte.Pour SQL Server 2008, un IN la liste est refactorisée en une série de OR déclarations.Cela peut être différent, par exemple, avec MySQL.

Je suis presque certain que si vous génériez des plans d'exécution réels pour vos deux requêtes, ils seraient identiques.

Selon toute vraisemblance, la deuxième requête s'est exécutée plus rapidement parce que tu l'as couru en deuxième, et la première requête avait déjà extrait toutes les pages de données de la base de données et payé le coût des E/S.La deuxième requête a pu lire toutes les données de la mémoire et s'exécuter beaucoup plus rapidement.

Mise à jour

La véritable source de la variance est probablement due au fait que les requêtes sont pas équivalent.Vous avez deux différents OR listes ci-dessous :

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'

et ensuite

 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'

Dans les deux WHERE clauses, la priorité des opérateurs (où AND est géré avant OR) signifie que la logique réelle exécutée par le moteur est :

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

Si vous remplacez le OR des listes avec un IN expression, la logique sera :

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

Ce qui est radicalement différent.

Autres conseils

La meilleure façon de le savoir est d'examiner le plan de requête réel en utilisant quelque chose comme EXPLAIN.Cela devrait vous dire exactement ce que fait le SGBD, et vous pourrez alors avoir une bien meilleure idée de pourquoi il est plus efficace.

Cela dit, les systèmes SGBD sont vraiment efficaces pour effectuer des opérations entre deux tables (comme les jointures).Une grande partie du temps de l'optimiseur est consacrée à ces parties des requêtes car elles sont généralement plus coûteuses.

Par exemple, le SGBD pourrait trier cela IN liste et, en utilisant un index sur item_desc, filtrez les résultats très rapidement.Vous ne pouvez pas effectuer cette optimisation lorsque vous répertoriez un ensemble de sélections comme dans le premier exemple.

Quand vous utilisez IN, vous créez un tableau impromptu et filtrez à l'aide de ces techniques de combinaison de tableaux plus efficaces.

MODIFIER:J'ai posté cette réponse avant qu'OP ne mentionne le SGBD spécifique.Il s'avère que ce n'est PAS la façon dont SQL Server traite cette requête, mais cela pourrait être valable pour d'autres systèmes SGBD.Voir La réponse de JNK pour une réponse plus précise et plus précise.

Licencié sous: CC-BY-SA avec attribution
scroll top