Skip to content
isdnetworks
Go back

강제한 인덱스가 만든 지연

조회가 느려서 실행 계획을 보니 인덱스가 있는데도 안 쓰고 전체를 읽고 있었다. 그래서 인덱스를 강제로 쓰게 했더니 오히려 두 배 넘게 느려지는 결과가 나왔다.

Table of contents

Open Table of contents

안 쓴 이유

그 조건에 실제로 매칭되는 건수를 세어 보니 전체의 20퍼센트 가까이였다. 인덱스로 그만큼을 찾으면 인덱스를 읽고 다시 행을 읽는 일이 매 건마다 일어난다.

그것보다 전체를 순서대로 읽는 편이 빨랐으므로 옵티마이저의 판단이 맞았다. 내가 인덱스를 쓰게 강제한 것이 나쁜 판단이었고 강제하기 전에 매칭 건수를 세었으면 알 수 있었다.

강제 대신 만든 인덱스

그래서 인덱스를 강제하는 대신 조건에 맞는 복합 인덱스를 새로 만들었다. 두 컬럼을 함께 걸자 읽어야 하는 행이 88만에서 1만 대로 줄었다.

응답 시간도 1.8초에서 0.02초 수준으로 떨어졌다. 강제는 있는 인덱스 중에 고르는 것이고 새로 만드는 것은 조건에 맞는 접근 경로를 여는 것이라 성격이 다르다.

컬럼 순서

복합 인덱스를 만들면서 컬럼 순서도 함께 정해야 했다. 각 조건의 매칭 건수만 놓고 보면 날짜 쪽이 훨씬 더 좁히고 있었다.

그런데 날짜는 범위 조건이라 그 뒤에 오는 컬럼은 인덱스를 못 쓰게 된다. 같음 조건을 앞에 두고 범위 조건을 뒤에 두는 것이 원칙이므로 매칭 건수만 보고 순서를 정하면 안 됐다.

통계가 낡은 경우

다른 쿼리에서는 실제로 통계가 낡아서 옵티마이저가 잘못 고르고 있었다. 통계를 갱신하고 다시 보니 접근 방식이 전체 읽기에서 인덱스 참조로 바뀌었다.

대량으로 넣거나 지운 뒤에는 통계가 실제와 달라질 수 있다. 그래서 인덱스를 강제하기 전에 통계부터 갱신해 보는 단계를 넣었다.

강제가 필요한 경우와 순서

그렇다고 모든 경우에 옵티마이저를 믿을 수 있는 것은 아니었다. 매칭이 열 몇 건뿐인데 정렬과 제한이 붙어 있으면 정렬을 피하려고 기본 키를 따라가면서 수백만 행을 읽는 경우가 있었다.

그런 경우는 정렬에 쓰는 컬럼을 인덱스에 포함시켜서 풀었다. 최종 순서는 실행 계획을 보고 매칭 건수를 세고 통계를 갱신한 뒤 조건에 맞는 인덱스를 만들고 그래도 안 되면 강제를 검토하되 강제한 것과 안 한 것을 둘 다 재서 비교하는 것으로 정했다.

정리


Share this post on:

Previous Post
이력이 없는 정상 흐름
Next Post
설정 옆에 근거를 적는다