옵티마이저 행동에 영향을 미치는 요소 

 - SQL과 연산자 형태 

     ● 결과 같더라도 SQL을 어떤 형태로 작성했는지 또는 연산자를 사용했느지에 따라 

         옵티마이저가 다른 선택을 할 수 있고, 궁극적으로 쿼리 성능에 영향을 미친다. 

 - 인덱스, IOT, 클러스터링, 파티셔닝, MV 등 옵티마이징 팩터 

 - 제약 설정 : PK, FK, Not Null, Check 

     ● PK 제약과 옵티마이저 

          예시) 서브쿼리를 Unnesting 하고서 서브쿼리 테이블 기준으로 NL 조인하려 할 때, 

                  만약 고객 테이블에 PK 제약이 없다면 고객번호 중복을 제거한느 sort unique 

                  오퍼레이션을 먼저 수행해야 한다. 

     ● FK 제약과 옵티마이저 

          예시) 조인 제거 기능과 FK 제약이 있을 때만 작동하는 기능들이 여러 있는데, 

                  11g에 추가된 Reference 파티셔닝도 그 중 하나다. 

     ● Not Null 제약과 옵티마이저 

          예시) where 절 없이, group by 절을 사용하면 index가 있다면 index full scan 또는 

                  index fast full scan으로 빠르게 처리할 수 있다. 하지만 이 경우 not null 제약이 

                  있어야 하며 not null 제약이 없을 시 null 값이 입력될 가능성을 염두에 두고 

                  실행계획을 수립해야 하므로 테이블 전체를 스캔한다. 

     ● Check 제약과 옵티마이저 

          예시) check 제약이 있을 시 where 절에 조건에 따라 filter 작업이 발생하지 않는다. 

                 파티션 뷰에서 참조하는 테이블에 check 제약을 설정하면 파티션 pruning 기능 작동


  - 옵티마이저 힌트 

      ● 옵티마이저 힌트가 제대로 작동하지 않는 경우 

           - 문법적으로 맞지 않게 힌트를 기술 

           - 잘못된 참조 사용 

           - 의미적으로 맞지 않게 힌트를 기술 

           - 논리적으로 불가능한 엑세스 경로 

           - 버그 

      ● 옵티마이저 힌트에 관한 일반적인 사용 원칙은 다음과 같다. 

           - 가급적 힌트 사용을 자제하고, 옵티마이저가 스스로 좋은 선택을 할 수 있도록 돕는다. 

           - 옵티마이저가 잘못된 선택을 할 때만 힌트를 사용한다.   

  - 통계정보 : 오브젝트 통계, 시스템 통계 

      ● CBO의 모든 판단 기준은 통계정보에서 나온다. 

  - 옵티마이저 관련 파라미터

      ● 만약 옵티마이저의 갑작스런 변화를 원치 않는다면 optimizer_features_enable 파라미터

           를 이전 버전으로 설정하면 된다.  

  - DBMS 버전과 종류 

옵티마이저란 

 - 오라클은 10g 이후로 CBO만 지원함 


규칙기반 옵티마이저 

 - 휴리스틱 옵티마이저 

 - OLTP 환경의 중소형 데이터베이스 시스템이라면 RBO 규칙이 어느 정도 보편 타당성을 갖는다.

   그러나 RBO는 대용량 데이터를 처리하는데 있어 합리적이지 못할 때가 많다. 


비용기반 옵티마이저 

 - 전통적인 I/O 비용 모델에서의 I/O 요청 횟수만으로 비용을 평가하지 않고, 

    CPU 연산 비용까지 감안하여 수행 일량을 상대적인 시간 개념으로 환산해서 비용을 평가 

 - CBO가 실행계획을 수립할 때 판단 기준이 되는 비용은 어디까지나 예상치 

 - 오브젝트 통계뿐만 아니라 하드웨어적 특성을 반영한 시스템 통계정보까지 이용 


최적화 수행단계를 요약 

  ● 사용자가 던진 쿼리수행을 위해 , 후보군이 될만한 실행계획을 찾는다. 

  ● 데이터 딕셔너리에 미리 수집해 놓은 오브젝트 통계 및 시스템 통계정보를 이용해 

        각 실행계획의 예상비용을 산정한다. 

  ● 각 실행계획의 비용을 비교해서 최저비용을 갖는 하나를 선택한다. 

 

동적 샘플링 

 - 만약 테이블과 인덱스에 대한 통계정보가 없거나 너무 오래돼 신뢰할 수 없을 때 옵티마이저가

    동적으로 샘플링을 수행하도록 할 수 있다. 

 - 통계 정보가 생성되지 않으면 하드 파싱 할때마다 동적 샘플링을 위한 recursive call 발생 

    ( 성능이 좋지 못하다. ) 


CBO를 기준으로 SQL 처리 절차 요약 

   ● Query Transformer 

   ● Estimator 

   ● Plan Generator


옵티마이저 모드  

 - rule 

 - all_rows 

    ● DML 문자은 일부 데이터만 가공하고 멈출 수 없으므로 옵티마이저 모드에 상관없이 

        항상 all_rows 모드로 작동한다. 

    ● Select 문장도 union, minus 같은 집합 연산자나 for update 절을 사용시 

        all_rows 모드로 작동

    ● PL/SQL 내에서 수행되는 SQL도 힌트를 사용하거나 기본 모드가 rule인 경우를 제외하면 

        항상 all_rows 모드로 작동 

 - first_rows

    ● first_rows는 비용과 규칙을 혼합한 형태의 옵티마이저 모드다.  

    ● 얼마만큼 fetch 할지 지정하지 않았으므로 정확한 비용을 예측할 수 없고, 

         따라서 옵티마이저 내부적으로 정해진 규칙을 사용한다. 

    ●  first_rows는 이제 과거 버전과의 호환성을 위한 용도로만 남게 되었다.  

 - first_rows_n 

    ● n으로 지정할 수 있는 값은 1, 10, 100, 1000 네 가지며, 사용자가 지정한 n개 로우이상을 

        Fetch 한다면 오히려 더 많은 리소스를 사용하고 전체 수행 속도도 느려질 수 있다. 

        (파라미터 사용 시 ) 

    ● 힌트를 사용할 때는 괄호 안에 () 보다 큰 어떤 정수 값이라도 입력 가능하므로 

        파라미터를 이용 할 때보다 더 정밀하게 제어할 수 있다. 

    ● first_rows_n은 완전한 CBO 모드로 작동한다. 

 - choose 

    ● 엑세스되는 테이블 중 적어도 하나에 통계정보가 있다면 CBO, 그중에서도 all_rows 모드를 

        선택한다. 

    ● 9i 까지는 choose가 기본 설정이었으나 10g부터는 all_rows가 기본 옵티마이저 모드로 

        설정된다.

         ( 통계정보 없는 테이블을 발견하면 무조건 동적 샘플링이 일어나기 때문에 

           RBO로 작동할 일이 없어진 것이다. )


옵티마이저 모드 선택 

 - first_rows 모드가 효과적인 애플리케이션 아키텍처는 주로 2-Tier 환경의 클라이언트/서버 구조

   이 애플리케이션 구조의 특징은 전체 결과집합이 아무리 많아도 사용자가 스크롤을 통해 

   일부만 Fetch하다가 멈춘다는 점이다. 결과집합을 끝까지 Fetch 하거나 다른 쿼리를 수행하기 

   전까지 SQL 커서는 오픈된 상태를 유지한다. 

 - OLTP성 애플리케이션이라도 3-Tier 구조는 클라이언트와 서버 간 연겨을 지속하지 않는 

   환경이므로 오프 커서를 계속 유지할 수 없어 페이지 처리 기법을 주로 사용한다. 

   이는 대량의 데이터에서 일부만 fetch 하다 멈추는 것이 아니라 집합 자체를 소량으로 

   정의한다는 것이다. 

 - 애플리케이션 특성상 확실히 first_rows가 적합하다는 판단이 서지 않는다면 all_rows를 

   기본 모드로 선택하고, 필요한 쿼리 또는 세션 레벨에서 first_rows 모드로 전환할 것을 권고 

누적 매출 구하기 

 - 8i부터 제공되기 시작한 분석함수를 이용하면 간단함 

 - 분석함수를 이용할 수 없는 상황에서 부등호 조인과 group by를 이용해 구할 수 있음 


선분이력 끊기 

 - greate, least 함수를 기억하라 

   (max, min이 수직적인 계산이라면, greate, least 행으로의 계산으로 이해하면 쉽다. ) 


데이터 복제를 통한 소계 구하기 

 - 오라클 9i부터는 dual 테이블을 사용하면 편하다. 

  * grouping sets 에 대한 테스트 내용 

     - grouping sets를 사용하면서도 기본적으로 그룹함수가 사용되지 않음 컬럼들은 

       group by절에 모두 사용 되어야 한다. 

    

상호배타적 관계의 조인 

 - 어떤 엔터티가 두 개 이상의 다른 엔터티의 합집합과 관계를 갖는 것을 

   '상호배타적 관계' 라고 한다 . 

    ( 여기서는 합집합 관계를 갇는 것을 상호배타적이라고 해서 헷갈렸다. 

       아직도 이건 잘못된 정의로 쓴 것 같다. ) 

 - 상호배타적인 관계의 경우 2가지 방법으로 테이블을 구성할 수 있다. 

     두 개의 컬럼을 두어서 각각 해당 되는 컬럼에 값을 입력하고 나머지는 null 처리 방법 

       - 이 경우는 outer 조인으로 간단하게 쿼리를 작성할 수 있다. 

     한 개의 컬럼을 두어서 해당 컬럼에 '1,2' 와 같이 값을 나누어서 넣는 방법

       - 이 경우는 union all을 활용하거나 

       - where 절에 decode 함수나 outer 조인을 활용한다.


최종 출력 건에 대해서만 조인하기 

 - 조인을 완료하여 order by를 하고 rownum 를 뽑아서 필요한 부분만 처리하는 경우 

   부하가 심하다.

 - 해당 부분에 부하를 줄이기 위하여 하나의 테이블의 컬럼들로 order by를 진행할 수 있고 

    해당 테이블이 인덱스가 where 조건에서 사용 되고 그로인하여 필터링이 다량 되어 

    최종 결과를 크게 줄일 수 있을 때, 해당 테이블의 where절과 order by를 우선적으로 실행하고

    거에서 rownum 값을 뽑아서 다른 테이블들과 조인을 시도 하는 방법이 있다. 

      * 나의 생각 

          - 그러나 이런한 경우는 위와 같이 제약이 많이 때문에 잘 따져보고 사용해야 한다. 

 

징검다리 테이블 조인을 이용한 튜닝

 - from절에서 조인되는 테이블 개수를 늘려 성능을 향상시키는 사례 

 - 최종 결과 건수는 얼마 되지 않으면서, 필터 조건만으로 각 부분을 따로 읽으면 결과 

   건수가 아주 많을 때 튜닝하기가 가장 어렵다. NL 조인 과정에서 Random I/O 부하가 심하게 

   발생하기 때문이며, 어느 쪽으로 드라이빙하더라도 결과는 마찬가지다. 


인조 식별자 사용에 으한 조인 성능 이슈 

 - 인조 식별자를 잘못 사용하게 되면 인덱스에 조건절을 실제 쿼리사 사용하지 못하여 

    더 많은 스캔을 발생 시킬 수도 있다. 


인조 식별자를 둘 때 주의 사항 

 - 인조식별자를 두면 PK, FK가 단일 컬럼으로 구성되므로 테이블 간 연결 구조가 단순해지고, 

   제약조건을 위해 사용되는 인덱스 저장공간이 최소화되는 장점이 있다. 그리고 다중 컬럼으로

   조인할 때보다 아무래도 조인 연산을 위한 CPU 사용량이 조금 줄 수 있다. 

 - 하지만 조인 연산할 때의 CPU 사용량 감소느 ㄴ아주 미밈한 수준이고, 오히려 앞서 설명한 

   사례처럼 조인 연산 횟수와 블록 I/O증가로 더 많은 시스템 리소스를 낭비하기 쉽다.  

 - 논리적이 데이터 모델링 단계에서는 가급적 인조 식별자를 두지 않는 것이 좋다. 

 - 의미상 주어에 해당하는 속성들을 그대로 식별자로 사용했다가 나중에 물리 설계 단계에서 

   저장 효율과 엑세스 효율등을 고려해 결정하는 것이 바람직하다.  


점이력 조회 

 - 데이터 변경이 발생할 때마다 변경일자와 함께 새로운 이력 레코드를 쌓는 방식 

  * 점이력 조회시 주의사항 

     - 원래 스칼라 서브쿼리를 사용하게 되면 버퍼 pinning 효과가 사라진다. 

        그러나 그룹 함수를 사용하게 되면 buffer pinning효과가 나타난다. 

        하지만 이 경우도 그룹함수에 들어가는 컬럼이 가공되면 buffer pinning 효과가 사라진다. 

 - 만약 2개 이상의 컬럼을 읽어야 한다면 스칼라 서브쿼리 내에서 필요한 컬럼 문자열을 

   연겨랗고, 메인 쿼리에서 substr 함수로 잘라 쓰는 방법을 사용해야 한다. 

 - 컬럼이 많아지만 스칼라 서브쿼리에서 rowid 값만 취하고 고객별연체이력을 한 번 더 

   조인하는 방법을 생각해 볼 수 있다. 

   ( 이 경우도 where절로 인하여 해당 되는 row수가 크게 줄을 때 효과가 클 것이다. )

 - where 절에 스칼라 서브쿼리를 사용하여 해당 되는 row들을 찾는 경우 

   서브쿼리에서 조인 절을 사용하였다면 따로 조인 조건을 기술해줄 필요 없고 

   버퍼 pinning도 사용할 수 있을 것으로 생각된다. 


정해진 시점 기준으로 조회 

 - 같은 테이블을 두번 사용해서 한 번은 조건을 줄이고 (정해진 시점으로) 다시 자신의 테이블에 

    조인해서 필요한 컬럼들을 뽑아 낼 경우, 그냥 필요한 컬럼들을 한번에 붙여서 

    substr를 사용해서 필요한 컬럼들만 뽑아 낼 수 있다. 

 - 분석 함수(max, min () over ) 보다는 row_number , rank 함수가 성능성 유리한다고 한다. 

   (이유에 대한 부분은 나온 것은 없고 책에는 테스트를 통해서만 이야기 하였다. )  


선분이력 조인 

 - 과거/현재/미래의 임의 시점 조회 

     과거 시점 between and 사용 

     현재 시점 종료일자 = '99991231'

                   ( 미래일자를 미리 입력하는 경우 sysdate 와 between and 사용 )

     임의의 시점 조회시 

        - 바로 그 시점을 조회시에는 

            해당 시점의 컬럼 과 between을 사용해서 쿼리 

          현재 시점의 종목명과 상장주식수를 출력시 

            sysdate와 between 을 사용해서 쿼리 

 

선분이력 조인 튜닝 

 - 선분이력에서는 where 절에 입력되는 조건값에 따라서 인덱스의 순서도 중요하다. 

    ( where 절에 입력되는 조건 값에 따라서 시작일이나 종료일 중 무엇이 앞에 오는 것이 

       유리 할 지 달라진다. ) 

 - Between 조인 튜닝은 조회 대상이 많지 않을 때 

 - 일반 조인문으로는 index , rownum 힌트로 튜닝할 수 없지만 조인 컬럼이 unique 한 값으로 

   소량만 조인이 되는 것이라면 하나의 테이블에서 그 양을 줄여준 다음 스칼라 서브 쿼리를 

   통해 index, rownum힌트를 사용하여 튜닝하는 것도  하나의 방법이 될 수 있다.

   ( 스칼라 서브쿼리의 특징을 사용하여 튜닝하는 방법으로 생각 됨  )  

 - 위의 방법을 사용하여 여러개의 컬럼을 출력할 경우는 스칼라 서브 쿼리에서 rowid 를 

   출력하고 다시 한 번 해당 rowid를 통해서 자신과 조인하는 방법이 있다. 

   ( 스칼라 서브쿼리에서 한 번만 출력하고 substr로 잘라 쓰는 방법도 있다. ) 

 - 또한, where 절에 스칼라 서브 쿼리를 써서 rowid 조인을 할 수도 있다.  

   ( 이 부분은 쿼리 실행 해석이 좀 재미 있는 부분이다. ) 

   * 위의 3가지 경우는 모두 같은 조건이 성립되어야 원하는 성능 튜닝이 제대로 될 것이다. 


Between 조인 튜닝 - 조회 대상이 많지만 대상별 이력 레코드가 많지 않을 때 

 - 만약 전체 고객을 대상으로 한다면 Random 엑세스 위주의 NL 조인보다 아래처럼 해시 

   조인을 이용하는 것이 효과적이다. 


Between 조인 튜닝 - 대상별 이력 레코드가 많을 때 

 - 대상별 이력 레코드가 많을 때의 between 조인이 가장 튜닝하기 어렵다. 

   ( 해시 조인을 하더라도 해당 키 값에 중복되는 것들이 많아서 해시 버킷에 해시 체인들이 

     많이 들어가서 해시 버킷을 읽는데 시간이 오래걸린다.  )

 - 이럴 때 글쓴이는 첫번째, 두 개 이상 월에 걸치는 이력이 생기기 않도록 매월 말일 시점에 

   강제로 이력을 끊어주는 것이다. 

    ( 해시 체인을 스캔하는 비효율을 완전히 없앨 수는 없지만 최대 31개가 넘지 않도록 

     제한하려는 것이다. ) 

 - 두 개 이상 월에 걸치는 이력이 없도록 쿼리 시점에 선분이력을 변환해주는 것이다. 

   그런 다음 조인하는 방법은 앞에서와 같고, 마찬가지로 해시 체인을 스캔하는 양은 

   최대 31개로 제한될 것이다. 

   ( 이 방식을 사용하면 '일별상품거래'와 조인할 때는 빠르지만, '월도' 테이블과 조인하는 

    과정에서 오히려 병목이 생길 수 있다. ) 


조인에 실패한 레코드 읽기 

 - 그 in (' ', c.지역) , max(지역) 이 들어간 쿼리를 말한다. 

   ( 조인이 될 수 없는 값들이 맨 마지막 값으로 쿼리 되는 것 ) 

+ Recent posts