콘텐츠로 이동

2023 11 07

2023-11-07

쿼리 튜닝하기

참고: https://techcourse.woowahan.com/s/O1qsxIcH/ls/wKz4Q505

1. 인덱스

  • 인덱스 칼럼은 가공해서 쿼리 날리거나 그런짓 하지 마세요
  • 인덱스 순서 고려하세요
    • 인덱스는 항상 정렬 상태를 유지해서 인덱스 순서에 따라 ORDER BY, GROUP BY 위한 소트 연산 생략할 수 있음
    • 조건절에 항상 사용하거나 자주 사용하는 칼럼을 인덱스로 선정할 것
    • = 조건으로 자주 조회하는 칼럼 앞쪽에
    • 하기 세가지 인덱스는 모두 중복
      1. 과세코드
      2. 과세코드 + 이름
      3. 과세코드 + 이름 + 연령
  • 인덱스 제대로 사용하는지 확인
    • 커버드 인덱스: 인덱스 스캔과정에서 얻은 정보만으로 처리할 수 있음. 테이블 액세스 발생 X
  • 복합 인덱스시 범위 검색 컬럼을 뒤에 둘 것
    • 범위 검색을 앞에 두면, 읽어야할 칼럼이 많아지는 지름길
    • 특정할 수 있는 걸 앞에 두는게 좋겠죠?

2. Join

  • 조인 연결 시, key들 모두 양쪽 다 인덱스를 가지고 있는 것이 좋음
    • 한쪽에만 인덱스가 있다면...
      • JoinBuffer를 사용하여 성능 개선을 하려곤 함
      • 일반적인 중첩 루프 조인에 비해 효율이 떨어짐
      • 테이블 크기와 상관없이 인덱스가 있는 테이블이 드라이빙 테이블이 되니 주의할 것
  • 데이터가 적은 테이블을 랜덤 액세스 할 것
    • 드라이빙 테이블의 데이터가 적다면, 중첩 루프 조인 수행하며 드리븐 테이블의 많은 양의 데이터에 인덱스 스캔
    • 드리븐 테이블의 PK 사용안한다면 많은 양의 데이터에 랜덤 액세스 해야함으로 비효율 적일 수 있음
  • 모수 테이블 크기를 줄일 것
  • 서브쿼리보다 조인문 쓸 것

Driving Table & Driven Table

참고: https://tlstjscjswo.tistory.com/entry/Nested-Loop-%EC%A1%B0%EC%9D%B8 참고: https://programming-workspace.tistory.com/67 참고: https://devlog.changhee.me/posts/Join%EA%B8%B0%EB%B2%95_%EC%A0%95%EB%A6%AC/

  • 드라이빙 테이블
    • 조인시 먼저 액세스 되는 쪽을 드라이빙 테이블
    • 나중에 액세스 되는 쪽을 드리븐 테이블로 지정
    • 인덱스의 존재 및 우선 순위, FROM 절에서의 Table 지정 순서에 따라 영향을 받음
    • 어느 테이블이 먼저 액세스 되느냐는 속도 차이가 크기에, 많은 양의 데이터 다룰시 드라이빙 테이블은 매우 중요
    • 결정 규칙
      • Cost-Based Optimizer
      • 소요되는 예상 비용을 바탕을 실행계획 생성
      • 통계정보, DBMS 설정정보, DBMS 버전에 따라 서로 다른 실행계획 1. 두 칼럼 모두 인덱스가 있다
        • 옵티마이저 판단으로 레코드 건수에 따라 드라이빙/드리븐 결정 2. 한쪽 컬럼에만 인덱스가 있다
        • 드리븐 테이블에 인덱스가 없다면 조인 과정에서 "드리븐 테이블을 매번 풀스캔하는 불상사"
        • 인덱스가 없는 테이블이 드라이빙 테이블이 되어버림 3. 두 칼럼 모두 인덱스가 없음
        • 어느 테이블을 드라이빙으로 해도 풀스캔 발생
        • 스캔되는 레코드 수에 따라 옵티마이저가 드라이빙 테이블 선택
        • 조인이 수행될 때 양쪽 테이블 컬럼에 모두 인덱스 업어야 드리븐 테이블 풀스캔
        • 왠만해선 옵티마이저가 드리븐 테이블 풀 스캔으로 접근 안해
  • 왜 드라이빙 테이블의 모수를 작게 가져가야하는걸까?
    • A 테이블이 5000만건, B 테이블이 1000만건일 경우...
    • A가 드라이빙이면 (B 테이블 5000만번 접근)
      • A 1행 -> B 찾기
      • A 2행 -> B 찾기 ...
      • A 5000만행 -> B 찾기 ...
    • B가 드라이빙이면 (A 테이블 1000만번 접근)
      • B 1행 -> A 찾기
      • B 2행 -> A 찾기
      • B 1000만행 -> A 찾기
    • 드라이빙 테이블은 옵티마이저가 정해줘
      • 인덱스는 걸려있니?
      • 레코드 건수나 통계정보는 어떠니?
  • Nested Loop Join
    • 정의: 연결고리가 되는 칼럼을 사용해, Driving Table과 Driven Table을 연결
    • 2개의 테이블이 루프를 돌며 연결고리 항목 추출하는 과정
    • 2차원 배열 중첩 for문 생각하면 딱
    • Driving 테이블의 사이즈가 크면 클수록 실행속도 저하됨!!!!

Hash Join vs Nested Loop Join

참고: https://jojoldu.tistory.com/173 참고: https://blog.naver.com/parkjy76/221069454499 참고: https://hoing.io/archives/14457

  • Nested Loop Join
    • 오라클에서는 여러 조인 알고리즘을 지원하지만 MySQL에서는 Nested Loop Join만 지원
    • 중첩반복을 사용하는 조인 알고리즘
      1. Table A에서 row 하나씩 반복해나가며 스캔 (Driving Table)
      2. Driving Table의 row 하나마다 내부 테이블의 레코드 하나씩 스캔해 Join 조건에 맞으면 리턴
      3. 1~2를 Driving Table의 모든 row에 반복
    • Nested Loop의 실행시간 = R(A) * R(B)
    • 여기서 대전제!
      • Inner Table의 조인키에는 인덱스가 걸려있어야 한다
    • Row가 적은 Driving Table을 쓰고 + Driven Table의 조인키에는 인덱스가 걸려있을 것
  • Block Nested-Loop
    • 결국... Nested Loop 조인만 지원하다보면 조인 칼럼 인덱스가 없으면 뇌절의 지름길
    • BNL이 없다면 드리븐 테이블을 스캔 or Index Full Scan => 성능 저하
    • BNL 방식은 프로세스 내에 별도 버퍼 (조인 버퍼)를 두고, Driving Table에 레코드를 저장한 뒤, Driven Table을 스캔하면서 조인 버퍼 탐색

IOT (Index Organized Table)

APM & AEM

HFA Proxy

DB 교체 과정