Pergunta

Eu estava trabalhando com uma consulta que escrevi hoje tive que alterar o código do WHERE cláusula para usar um filtro IN(lista de coisas) em vez de usar algo como

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

O procedimento acima durou 15 minutos e não retornou nada, mas o seguinte me deu meu resultado definido em 1,5 minutos

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

Fiz isso em SQL e estou me perguntando por que IN (lista de itens) teve um desempenho muito mais rápido que a instrução OR.

- Editar- SQL Server 2008, peço desculpas por não colocar esse pouco de informação em primeiro lugar.

Aqui está a consulta na íntegra usando o OR declarações:

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

Obrigado,

Foi útil?

Solução

A resposta de Oleski está incorreta.Para o SQL Server 2008, um IN lista é refatorada para uma série de OR declarações.Pode ser diferente, digamos, no MySQL.

Tenho quase certeza de que se você gerasse planos de execução reais para ambas as consultas, eles seriam idênticos.

É muito provável que a segunda consulta tenha sido executada mais rapidamente porque você executou em segundo lugar, e a primeira consulta já extraiu todas as páginas de dados do banco de dados e pagou o custo de IO.A segunda consulta foi capaz de ler todos os dados da memória e executar muito mais rápido.

Atualizar

A origem real da variação é provável que as consultas sejam não equivalente.Você tem dois diferentes OR listas abaixo:

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 depois

 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'

Em ambos aqueles WHERE cláusulas, a precedência do operador (onde AND é tratado antes de OR) significa que a lógica real executada pelo mecanismo é:

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

Se você substituir o OR listas com um IN expressão, a lógica será:

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

O que é radicalmente diferente.

Outras dicas

A melhor maneira de saber é observar o plano de consulta real usando algo como EXPLAIN.Isso deve dizer exatamente o que o SGBD está fazendo, e então você poderá ter uma ideia muito melhor de por que ele é mais eficiente.

Dito isso, os sistemas SGBD são realmente bons em realizar operações entre duas tabelas (como junções).Muito do tempo do otimizador é gasto nessas partes das consultas porque geralmente são mais caras.

Por exemplo, o SGBD poderia classificar isso IN lista e, usando um índice em item_desc, filtre os resultados muito rapidamente.Você não pode fazer essa otimização ao listar várias seleções, como no primeiro exemplo.

Quando você usa IN, você está criando uma tabela improvisada e filtrando usando essas técnicas mais eficientes de combinação de tabelas.

EDITAR:Publiquei esta resposta antes que o OP mencionasse o DBMS específico.Acontece que NÃO é assim que o SQL Server trata essa consulta, mas pode ser válido para outros sistemas DBMS.Ver A resposta de JNK para uma resposta mais específica e precisa.

Licenciado em: CC-BY-SA com atribuição
scroll top