-
SQL BOOSTER - SQL 작성 가이드 (2)DataBase/SQL 2024. 7. 15. 09:43
1. 불필요한 COUNT는 하지 않는다.
COUNT(*)는 데이터 건수를 세는 집계함수이다. 데이터 존재 여부를 확인하기 위해 COUNT(*)를 사용하는 경우가 많다.
SELECT COUNT(*) FROM T_ORD_BIF T1 WHERE T1.ORD_YMD = '20170225' AND T1.CUS_ID = 'CUS_0006';
실행계획을 보면 INDEX RANGE SCAN단계의 A-ROWS가 10,000건이다. 카운트 했기 때문에 주문을 모두 읽은 것이다.
단발성 SQL이라면, 큰 부담이 없겠지만,
고객이 주문할 때마다 실행되는 SQL이라면, 최적화할 필요가 있다.
SELECT NVL(MAX(1),0) FROM DUAL A WHERE EXISTS( SELECT * FROM T_ORD_BIG T1 WHERE T1.ORD_YMD = '20170225' AND T1.CUS_ID = 'CUS_0006' );
이와 같이 최적화 할 수 있다. INDEX RANGE SCAN A-Rows가 1이다. Bufferes 수치도 4밖에 되지 않는다.
2. COUNT에 불필요한 부분은 제거한다.
SELECT T1.ORD_SEQ, T1.RNO, T1.ORD_YMD, T1.CUS_ID, T2.CUS_NM, T3.BAS_CD_NM ORD_ST_NM FROM T_ORD_BIG T1, M_CUS T2, C_BAS_CD T3 WHERE T1.ORD_YMD = '20170107' AND T2.CUS_ID = T1.CUS_ID AND T3.LNG_CD = 'KO' AND T3.BAS_CD_DV = 'ORD_ST' AND T3.BAS_CD = T1.ORD_ST ORDER BY T1.ORD_SEQ, T1.RNO;
주문정보와 함께 고객이름을 보여주기 위해 고객 테이블과 조인하고 있다. 지금은 크게 문제될 것이 없다.
다만, 위 SQL의 전체 건수를 보여주기 위해 아래와 같은 패턴으로 개발할 수도 있다.
SELECT COUNT(*) FROM ( SELECT T1.ORD_SEQ, T1.RNO, T1.ORD_YMD, T1.CUS_ID, T2.CUS_NM, T3.BAS_CD_NM ORD_ST_NM FROM T_ORD_BIG T1, M_CUS T2, C_BAS_CD T3 WHERE T1.ORD_YMD = '20170107' AND T2.CUS_ID = T1.CUS_ID AND T3.LNG_CD = 'KO' AND T3.BAS_CD_DV = 'ORD_ST' AND T3.BAS_CD = T1.ORD_ST ORDER BY T1.ORD_SEQ, T1.RNO; ) T;
이 패턴은 SQL을 추가 개발할 필요가 없어 매우 편리하다. 하지만 이와 같은 방법은 SQL 성능에 손해를 본다.
카운트 결과에 영향을 주지 않는 조인과 ORDER BY를 그대로 사용했기 때문이다.
실행계획을 보면 두 번의 조인이 있다. 조인을 모두 수행한 후에 COUNT 처리가 되었다.
생각해보면 고객명과 ORD_ST 코드명, ORDER BY는 COUNT하는데 전혀 상관이 없다.
SELECT COUNT(*) FROM T_ORD_BIG T1 WHERE T1.ORD_YMD = '20170107';
이와 같이 처리해도 결과에는 아무런 영향이 없다! 따라서 COUNT시 불필요한 조인과 ORDER BY는 사용하지말자
3. 불필요한 컬럼은 사용하지 않는다.
SQL을 작성하다보면, 필요한 컬럼을 일일이 적기 번거로워 SELECT *을 사용하기도 한다.
일회성으로 실행하는 SQL이라면 SELECT *을 사용해도 특별히 문제는 없다. 하지만 실제 서비스하는 SQL이라면 꼭 필요한 컬람만 SELECT에 적어주는 것이 좋다.
이는 인덱스 때문이다. 복합 인덱스를 걸어두고 *로 읽으면, TABLE ACCESS BY INDEX ROWID작업이 추가되지만, 인덱스와 동일한 컬럼만 조회하는 경우에는 해당 작업을 줄일 수 있다.
어느정도 TABLE ACCESS BY INDEX ROWID 작업이 발생하는 것은 성능에 큰 문제는 없지만, 줄일 수 있는 부하는 줄여주는 것이 좋으므로, 필요한 컬럼만 SELECT 절에 사용하는 습관을 가지도록 하자
4. 동일한 테이블의 반복 서브쿼리를 제거하자
SELECT절의 서브쿼리는 필요한 곳에 적절히 사용하면 SQL 성능과 가독성에 큰 도움이 된다.
하지만 무분별하게 사용하면 데이터베이스의 성능을 떨어뜨리는 주범이 된다.
SELECT T1.ORD_SEQ, T1.CUS_ID, T1.ORD_ST , (SELECT A.CUS_NM FROM M_CUS A WHERE A.CUS_ID = T1.CUS_ID) CUS_NM , (SELECT A.EML_DA FROM M_CUS A WHERE A.CUS_ID = T1.CUS_ID) EML_AD FROM T_ORD T1;
고객명과 이메일 주소를 가져오기 위해 SELECT 절에 두 개의 서브쿼리를 사용했다.
서브쿼리도 조인의 일종이다. 그러므로 위와 같이 SQL을 작성하면 M_CUS 테이블을 두 번 조인한 것과 같다.
위 SQL은 한 번의 조인으로 변경할 수 있다.
반복되는 SELECT 절 서브쿼리는 조인으로 작성하도록 하자
단, 코드명과 같이 값의 종류가 많지 않은 경우 서브쿼리를 사용하는 것도 괜찮다.
서브쿼리 캐싱으로 성능이 향상될 수 있다.
반복 출현하는 테이블을 무리하게 합치려다 오히려 성능이 나빠질 수도 있다. 따라서 반복 출현하는 SELET 서브쿼르는 하나로 합치는 것이 기본 원칙이지만 가장 중요한 것은 실행계획을 보고 성능에 문제가 없는지 확인하는 것이다.
'DataBase > SQL' 카테고리의 다른 글
SQL BOOSTER - SQL 작성 가이드(3) (0) 2024.07.15 SQL BOOSTER - SQL 개발 가이드 (0) 2024.07.12 SQL BOOSTER 페이징 기술 (0) 2024.07.11 SQL BOOSTER - 분석함수 (0) 2024.07.10 SQL BOOSTER - 문서번호 처리 기술 (0) 2024.07.09