ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SQL BOOSTER - 복합인덱스
    DataBase/SQL 2024. 6. 12. 15:13

     

    복합 인덱스 - 컬럼 순정과 순서 

     

    A,B,C 칼럼 순서의 복합 인덱스와 C,B,A 컬럼 순서의 복합 인덱스는 완전히 다른 인덱스다 

     

    복합 인덱스를 만들 때 가장 중요한 것은 인덱스를 구성하는 컬럼 순서다. 

    어떤 순서로 컬럼을 정하는 지에 따라 강력한 성능을 발휘할 수도 있으며, 도움이 안 될 수도 있다. 

     

    이때, 컬럼 순서를 정할 때 관심 있게 봐야하는 것은 WHERE절의 조건이다. 

    • 같다 조건이 사용된 컬럼을 복합 인덱스에 앞 부분에 두는 것이 기본 원칙이다. 
    CREATE INDEX X_T_ROD_BIG_$ ON T_ORD_BIF(CUS_ID,ORD_YMD);
    
    SELECT /*+GATHER_PLAN_STATISTICS INDEX(T1 X_T_ORD_BIG_3) */
    T1.ORD_ST, COUNT(*)
    FROM T_ORD_BIG T1
    WHERE T1.ORD_YMD LIKE '201703%'
    AND T1.CUS_ID = 'CUS_0075'
    GROUP BY T1.ORD_ST;
    • CUS_ID가 = 조건이므로, 복합 인덱스에 앞에 두었다.

    SQL BOOSTER

     

    INDEX RANGE SCAN의 Bufferes를 보자, 이전보다 약 7000블록 정도의 IO를 개선했다. 

     

    SQL BOOSTER

     

    그림 가운데 인덱스의 리프 블록 데이터를 보면, ORD_YMD 순서로 먼저 정렬하고, CUS_ID로 정렬한 것을 볼 수 있다. 

     

    선두 컬럼 ORD_YMD는 LIKE 조건이 사용되었다. INDEX RANGE SCAN에서 가장 먼저 할 일은 루트에서 검색을 시작할 리프를 찾아가는 것이다. 근데, 복합 인덱스의 선두 컬럼이 범위 조건으로 되면, 인덱스의 두 번째 컬럼은 리프 검색 위치 알아내는데 관여하지 못한다. 

     

    또한 찾고자하는 CUS_ID가 ORD_YMD별로 흩어져 있으므로, 스캔 과정에서 CUS_ID도 읽는 비효율이 발생한다. 

     

    SQL BOOSTER

     

    그림 가운데 리프 블록을 보면 CUS_ID 순서로 먼저 정렬되고, ORD_YMD순서로 정렬되어 있다. 

    복합 인덱스의 선두 컬럼이 같다 조건으로 사용되어야만 두 번째 컬럼도 리프 블록 검색 시작 위치를 찾는데 관여할 수 있다. 

     

    리프의 시장위치를 보면, CUS_0075이면서 ORD_YMD가 20170301이다. 

    SQL BOOSTER

     

    조인이 포함되면, 조인 조건까지 생각해서 인덱스 칼럼 순서를 결정해야한다. 

    위 공식을 외우지말고, 인덱스에 따라 IO가 어떻게 변경되는지 추적해보면서 최적의 인덱스를 찾아야한다. 

     


    컬럼 선정과 순서 (2)

     

    이번에는 ORD_YMD가 같다 조건, CUS_ID에는 범위 조건이 사용된 SQL을 살펴보자면, 

    하나의 SQL에는 효율적이고, 다른 SQL에는 비율적일 수 있다. 따라서 SQL에 따라 적절한 인덱스를 사용해야한다.

     

    컬럼 선정과 순서(3)

     

    SELECT T1.ORD_ST,COUNT(*)
    FROM T_ORD_BIG T1
    WHERE T1.ORD_YMD LIKE '2017%4'
    AND T1.CUS_ID = 'CUS_0042'
    AND T1.PAY_TP = 'BANK'
    GROUP BY T1.ORD_ST;

    3개 조건이 사용된 SQL에 복합인덱스의 컬럼 후보로 ORD_YMD,CUS_ID,PAY_TP가 있다.

    같다 조건이 사용된 컬럼이 선두로 오면 좋기 때문에 다음 케이스를 고민할 것이다.

     

    1. CUS_ID,PAY_TP,ORD_YMD

    2. PAY_TP,CUS_ID,ORD_YMD

     

    위 SQL 성능만 해결하고자 한다면, 1번과 2번 둘 중 어느 순서로 만들어도 상관없다.

    다만, 이럴땐 다른 SQL도 신경써두자 

     

    SELECT 'X'
    FROM DUAL A
    WHERE EXISTS(
    
    	SELECT * 
        FROM T_ORD_BIG T1
        WHERE T1.CUS_ID = 'CUS_0042'
    );

     

    EXISTS 절에서 CUS_ID컬럼을 같다 조건으로 사용하고 있다. 시스템에 이와 같은 SQL도 있다면, 1번 순서가 더 아능 ㄴ선택이다. 

    오라클에는 INDEX SKIP SCAN 기능이 있어, 복합 인덱스의 가운데 컬럼을 인덱스 검색에 어느정도 활용할 수 있다.

     

    또한, 업무적으로 CUS_ID가 같다 조건으로 사용될 사능성이 매우 높다 그러므로, CUS_ID 컬럼을 복합 인덱스의 선두에 놓는 것이 좋다 

     


    컬럼 선정과 순서 (4)

     

    SELECT COUNT(*)
    FROM T_ORD_BIG T1
    WHERE T1.ORD_AMT = 2400
    AND T1.PAY_TP = 'CARD'
    AND T1.ORD_YMD = '20170406'
    AND T1.ORD_ST = 'COMP'
    AND T1.CUS_ID = 'CUS_0036';
    
    -- 해당 SQ의 인덱스를 고르고 싶다면 조건별로 카운트 해보자 
    
    SELECT 'ORD_AMT' COL, COUNT(*) FROM T_ORD_BIG T1 WHERE T1.ORD_AMT =2400
    UNION ALL 
    SELECT 'PAY_TP' COL, COUNT(*) FROM T_ORD_BIG T1 WHERE T1.PAY_TP ='CARD'
    UNION ALL 
    SELECT 'ORD_YMD' COL, COUNT(*) FROM T_ORD_BIG T1 WHERE T1.ORD_YMD ='20170406'
    UNION ALL
    SELECT 'ORD_ST' COL, COUNT(*) FROM T_ORD_BIG T1 WHERE T1.ORD_ST ='COMP'
    UNION ALL
    SELECT 'CUS_ID' COL, COUNT(*) FROM T_ORD_BIG T1 WHERE T1.CUS_ID ='CUS_0036'

     

    위 SQL에는 다섯 개의 조건이 있다. 

     

    SQL BOOSTER

     

    어떤 조건이 성능에 도움이 되는지 알 수 있다. ORD_YMD 조건은 90,000건의 데이터를 찾아내고, CUS_ID 조건은 330,000건의 데이터를 찾아낸다. 아마도 ORD_YMD와 CUS_ID로 복합 인덱스를 구성하면 충분히 성능이 나올 것이다.

    다른 조건들은 성능에 큰 도움이 안된다. 

     

    이를 토대로 인덱스를 만들고, SQL을 실행하면 다음과 같은 실행계획이 나온다. 

     

    SQL BOOSTER

     각 단계의 A-Rows를 살펴보면 INDEX RANGE SCAN단계와 TABLE ACCESS BY INDEX ROWID가 모두 10000이다.

    인덱스에서 찾아낸 데이터 모두가 최종 결과에 포함되었으므로, 비효율이 전혀 없다. 

     


    결론

     

    • 같다 조건이 사용된 컬럼이 복합 인덱스의 앞부분에 위치해야 한다.
    • 인덱스를 만들 때, 해당 테이블에 대한 SQL 전체를 검토하도록 한다.(모든 SQL을 검토할 수 없다면, 최대한 많은 SQL을 검토한다)
    • 조건에 사용된 모든 컬럼을 무조건 복합 인덱스에 추가해서는 안된다. (성능에 도움이 되는 조건 컬럼만 선별해서 복합 인덱스를 구현하도록 한다.)
Designed by Tistory.