문제

오늘 작성한 쿼리로 작업 중 코드를 변경해야 했습니다. WHERE 다음과 같은 것을 사용하는 대신 IN(list of stuff) 필터를 사용하는 절

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

위의 내용은 15분 동안 실행되었으며 아무 것도 반환되지 않았지만 다음은 1.5분 만에 설정된 결과를 제공했습니다.

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

SQL에서 이 작업을 수행했는데 왜 IN(항목 목록)이 OR 문보다 훨씬 빠르게 수행되는지 궁금합니다.

- 편집- SQL Server 2008,이 정보를 처음에 넣지 않은 것에 대해 사과드립니다.

다음은 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

감사합니다,

도움이 되었습니까?

해결책

Oleski의 답변이 잘못되었습니다.SQL Server 2008의 경우 IN 목록은 일련의 목록으로 리팩토링됩니다. OR 진술.MySQL에서는 다를 수 있습니다.

두 쿼리 모두에 대한 실제 실행 계획을 생성했다면 동일할 것이라고 확신합니다.

아마도 두 번째 쿼리가 더 빨리 실행되었을 것입니다. 당신이 두 번째로 실행했기 때문에, 첫 번째 쿼리는 이미 데이터베이스에서 모든 데이터 페이지를 가져와 IO 비용을 지불했습니다.두 번째 쿼리는 메모리에서 모든 데이터를 읽고 훨씬 빠르게 실행할 수 있었습니다.

업데이트

차이의 실제 원인은 쿼리가 다음과 같을 가능성이 높습니다. 동일하지 않음.당신은 서로 다른 두 가지를 가지고 있습니다 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'

그리고 나중에

 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'

그 둘 모두에서 WHERE 절, 연산자 우선 순위(AND가 OR보다 먼저 처리됨)는 엔진에서 실행되는 실제 논리가 다음과 같다는 것을 의미합니다.

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

교체하면 OR 목록에 IN 표현식의 경우 논리는 다음과 같습니다.

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

근본적으로 다릅니다.

다른 팁

가장 좋은 방법은 다음과 같은 것을 사용하여 실제 쿼리 계획을 살펴보는 것입니다. EXPLAIN.이를 통해 DBMS가 수행하는 작업을 정확하게 알 수 있으며, 그러면 왜 더 효율적인지 훨씬 더 잘 이해할 수 있습니다.

즉, DBMS 시스템은 조인과 같은 두 테이블 간의 작업을 수행하는 데 정말 능숙합니다.쿼리의 이러한 부분은 일반적으로 비용이 더 많이 들기 때문에 최적화 프로그램의 시간이 많이 소요됩니다.

예를 들어 DBMS는 다음을 정렬할 수 있습니다. IN 목록과 색인을 사용하여 item_desc, 결과를 매우 빠르게 필터링합니다.첫 번째 예와 같이 여러 선택 항목을 나열하면 해당 최적화를 수행할 수 없습니다.

당신이 사용할 때 IN, 즉석 테이블을 만들고 이러한 보다 효율적인 테이블 결합 기술을 사용하여 필터링하고 있습니다.

편집하다:OP가 특정 DBMS를 언급하기 전에 이 답변을 게시했습니다.이는 SQL Server가 이 쿼리를 처리하는 방식이 아닌 것으로 밝혀졌지만 다른 DBMS 시스템에는 유효할 수 있습니다.보다 JNK의 답변 보다 구체적이고 정확한 답변을 위해

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 softwareengineering.stackexchange
scroll top