2023 11 07
2023-11-07¶
쿼리 튜닝하기¶
참고: https://techcourse.woowahan.com/s/O1qsxIcH/ls/wKz4Q505
1. 인덱스¶
- 인덱스 칼럼은 가공해서 쿼리 날리거나 그런짓 하지 마세요
- 인덱스 순서 고려하세요
- 인덱스는 항상 정렬 상태를 유지해서 인덱스 순서에 따라 ORDER BY, GROUP BY 위한 소트 연산 생략할 수 있음
- 조건절에 항상 사용하거나 자주 사용하는 칼럼을 인덱스로 선정할 것
=조건으로 자주 조회하는 칼럼 앞쪽에- 하기 세가지 인덱스는 모두 중복
- 과세코드
- 과세코드 + 이름
- 과세코드 + 이름 + 연령
- 인덱스 제대로 사용하는지 확인
- 커버드 인덱스: 인덱스 스캔과정에서 얻은 정보만으로 처리할 수 있음. 테이블 액세스 발생 X
- 복합 인덱스시 범위 검색 컬럼을 뒤에 둘 것
- 범위 검색을 앞에 두면, 읽어야할 칼럼이 많아지는 지름길
- 특정할 수 있는 걸 앞에 두는게 좋겠죠?
2. Join¶
- 조인 연결 시, key들 모두 양쪽 다 인덱스를 가지고 있는 것이 좋음
- 한쪽에만 인덱스가 있다면...
- JoinBuffer를 사용하여 성능 개선을 하려곤 함
- 일반적인 중첩 루프 조인에 비해 효율이 떨어짐
- 테이블 크기와 상관없이 인덱스가 있는 테이블이 드라이빙 테이블이 되니 주의할 것
- 한쪽에만 인덱스가 있다면...
- 데이터가 적은 테이블을 랜덤 액세스 할 것
- 드라이빙 테이블의 데이터가 적다면, 중첩 루프 조인 수행하며 드리븐 테이블의 많은 양의 데이터에 인덱스 스캔
- 드리븐 테이블의 PK 사용안한다면 많은 양의 데이터에 랜덤 액세스 해야함으로 비효율 적일 수 있음
- 모수 테이블 크기를 줄일 것
- 서브쿼리보다 조인문 쓸 것
- 참고: https://stackoverflow.com/questions/2577174/join-vs-sub-query
- 주로 조인이 성능 좋음
- 서브쿼리는 A로 부터 이걸 가져오고 B로 부터 조건적으로 이걸 가져오는 느낌
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만 지원
- 중첩반복을 사용하는 조인 알고리즘
- Table A에서 row 하나씩 반복해나가며 스캔 (Driving Table)
- Driving Table의 row 하나마다 내부 테이블의 레코드 하나씩 스캔해 Join 조건에 맞으면 리턴
- 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을 스캔하면서 조인 버퍼 탐색