느린 검색을 개선하려고 인덱스를 셋 설계해서 추가하고 배포까지 했다. 넣기 전에 실행계획으로 확인까지 했는데 체감 개선이 없다는 말을 들었다.
Table of contents
Open Table of contents
인덱스를 넣었는데 체감이 없었다
추가하기 전에 확인한 실행계획에서는 분명히 새 인덱스를 타고 있었다. 그러면 확인 자체가 잘못됐거나 확인한 것과 실제로 도는 것이 다르다는 뜻이다.
돌이켜 보니 내가 실행계획에 넣은 조건은 손으로 직접 쓴 것이었다. 그것이 앱이 실제로 만드는 조건과 같은지는 한 번도 확인한 적이 없었다.
손으로 쓴 조건과 앱이 만드는 조건
쿼리 빌더 코드를 따라가니 조건 하나가 두 항목을 묶은 형태로 조립되고 있었다. 내가 실행계획에 넣었던 조건에는 그 묶음 부분이 아예 없었다.
손으로 쓰면 핵심 조건만 남기고 무의식적으로 단순화하므로 인덱스가 잘 도는 것처럼 보인다. 실제 조건을 그대로 넣어 다시 돌리니 새 인덱스를 아예 안 타고 있었다.
OR가 막은 인덱스
두 항목을 묶은 조건이 각각은 인덱스로 찾을 수 있는데 하나로 묶이면 단일 인덱스로 커버가 안 된다. 옵티마이저는 정렬 순서를 얻을 수 있는 기본 키로 물러났다.
정렬과 개수 제한이 붙어 있으니 역순으로 훑다가 필요한 만큼 찾으면 멈추는 편이 낫다고 본 것이다. 인덱스가 있어도 조건의 형태가 그것을 못 쓰게 만든 경우였다.
거짓이던 설계 전제
인덱스를 설계할 때 마스터 상품은 특정 컬럼이 비어 있다는 전제를 깔고 있었다. 그 전제가 맞는지 실제로 세어 보니 해당 조합의 행이 하나도 없었다.
마스터 상품은 그 컬럼에 값이 들어 있었으므로 전제가 처음부터 거짓이었다. 틀린 전제 위에서 만든 인덱스라 조건을 못 좁히는 것이 당연한 결과였다.
절반을 넘는 조건과 세 방안
이 조건이 실제로 몇 건을 잡는지 세어 보니 전체의 절반을 넘었다. 절반을 넘게 잡는 조건은 인덱스로 좁혀지지 않으므로 인덱스를 더 넣어도 해결되지 않는다.
조건을 나눠 각각 인덱스를 타게 한 뒤 합치거나 병합이 가능하도록 별도 인덱스를 두거나 조건 자체를 계산 컬럼으로 만들어 거는 셋이 남았다. 인덱스 추가가 아니라 쿼리 구조나 스키마를 바꾸는 쪽으로 가야 하는 자리였다.
정리
- 인덱스를 넣고 체감이 없으면 실제 생성 쿼리를 역추적한다
- 실행계획에 넣는 조건은 앱이 만드는 것이어야 한다
- 손으로 쓰면 단순화되어 인덱스가 잘 도는 것처럼 보인다
- 두 항목을 묶은 조건은 단일 인덱스로 커버가 안 된다
- 정렬과 개수 제한이 있으면 기본 키 역순으로 물러난다
- 설계의 전제 자체가 거짓일 수 있으므로 세어서 확인한다
- 조건이 전체의 절반을 넘으면 인덱스로 안 줄어든다
- 그때는 쿼리 구조나 스키마를 바꾼다