본문 바로가기
SQL

[SQL 쿼리 속도] JOIN 조건 추가보다 UNION ALL이 빠를 수 있다

by 펜네임 2021. 7. 14.

*MSSQL 기준

 

 공부배경 

새로 유지보수를 맡게 된 메뉴의 프로시저를 분석하는데 프로시저가 너무 길고 읽기 복잡했다.

일단 처음부터 끝까지 분석해 프로시저의 전반적인 내용은 다 파악했다.

그 다음으로 사수에게 반영을 제안할만한 리팩토링 방법을 찾아보기로 했다.

프로시저에 INNER JOIN 조건만 다른 쿼리 두 개가 UNION ALL 되어 있는 부분이 있었다.

쿼리 한 개에 조인 조건을 몰아넣어 주고 UNION ALL을 없애 코드 길이를 줄여봤다.

 

 

 1. UNION ALL을 쓴 쿼리 

   - 쿼리 길이 51줄 / 실행속도 평균 약 0.58초

  SELECT 
         CASE 
             WHEN B.AA IS NULL
                  OR B.AA = 'aa'
             THEN '1'
             ELSE '2' 
         END AS TYPE , 
         A.BB , 
         A.CC , 
         A.DD , 
         (
             CASE 
                 WHEN A.TIME <= '0800' 
                 THEN CONVERT(INT,A.TIME) + '2400' 
                 ELSE A.TIME 
             END
         ) AS TIME_FOR_CAL
    FROM TABLE_1 A
     INNER JOIN VIEW_1 V 
         ON (V.SEQ = '123' AND V.NUM = '123'+'_'+ A.ID) 	-- SEQ가 123
         AND V.STATUS = '9' 
     LEFT OUTER JOIN TABLE_2 B
         ON B.DATE = A.DATE 
   WHERE DATE BETWEEN @FROMDATE AND @TODATE
	   
UNION ALL
    
  SELECT 
         CASE 
             WHEN B.AA IS NULL
                  OR B.AA = 'aa'
             THEN '1'
             ELSE '2' 
         END AS TYPE , 
         A.BB , 
         A.CC , 
         A.DD , 
         (
             CASE 
                 WHEN A.TIME <= '0800' 
                 THEN CONVERT(INT,A.TIME) + '2400' 
                 ELSE A.TIME 
             END
         ) AS TIME_FOR_CAL
    FROM TABLE_1 A
     INNER JOIN VIEW_1 V 
         ON (V.SEQ = '456' AND V.NUM = '456'+'_'+ A.ID) 	-- SEQ가 456
         AND V.STATUS = '9' 
     LEFT OUTER JOIN TABLE_2 B
         ON B.DATE = A.DATE 
   WHERE DATE BETWEEN @FROMDATE AND @TODATE


 2. UNION ALL 대신 INNER JOIN 조건을 추가한 쿼리 

  - 쿼리 길이 26줄 / 실행속도 평균 약 0.75초

  SELECT 
         CASE 
             WHEN B.AA IS NULL
                  OR B.AA = 'aa'
             THEN '1'
             ELSE '2' 
         END AS TYPE , 
         A.BB , 
         A.CC , 
         A.DD , 
         (
             CASE 
                 WHEN A.TIME <= '0800' 
                 THEN CONVERT(INT,A.TIME) + '2400' 
                 ELSE A.TIME 
             END
         ) AS TIME_FOR_CAL
    FROM TABLE_1 A
     INNER JOIN VIEW_1 V 
         ON ((V.SEQ = '123' AND V.NUM = '123'+'_'+ A.ID) 	-- SEQ가 123
         	OR
            (V.SEQ = '456' AND V.NUM = '456'+'_'+ A.ID))	-- SEQ가 456
         AND V.STATUS = '9' 
     LEFT OUTER JOIN TABLE_2 B
         ON B.DATE = A.DATE 
   WHERE DATE BETWEEN @FROMDATE AND @TODATE

 

 결론 

조인 조건이 많은 쿼리 하나를 돌리는 것보다
조인 조건이 적은 쿼리 두 개를 UNION ALL하여 돌리는 것이 더 빠를 수 있다.

 

테스트에서 조회된 레코드는 44줄이었는데,

실제 사용 시에는 더 많은 데이터를 불러오는 경우가 대부분이라 속도 차가 더 클 것이다.

 

읽기 쉬운 코드가 항상 효율적인 코드는 아니라는 건 알고 있었는데,

테스트 해보며 직접 눈으로 확인하니 공부가 됐다.

 

 

추가내용 / 2021.7.20

조인에 OR 조건이 추가되더라도

UNION ALL 대신 적절한 인덱스를 사용하는 것이 더 빠를 수 있다고 한다.

댓글