Skip to content
isdnetworks
Go back

선행 컬럼이 없으면 인덱스가 죽는다

백만 건이 넘는 데이터를 다루는 쿼리가 느려서 실행계획을 봤다. 수백만 행을 훑으면서 임시 테이블과 파일 정렬까지 붙어 있었다.

Table of contents

Open Table of contents

실행계획이 고른 다른 인덱스

실행계획이 쓰고 있는 인덱스는 우리 조건과 무관한 것이었다. 선택도가 낮아서 대량으로 훑은 뒤에 조건을 검사하는 형태였다.

그러면 왜 조건에 맞는 인덱스를 안 쓰는지가 다음 물음이다. 실행계획만 보면 다른 것을 쓴다는 사실까지이고 이유는 인덱스 정의를 봐야 나온다.

선행 컬럼이 조건에 없었다

인덱스 목록을 보니 우리가 쓰는 두 컬럼이 복합 인덱스의 세 번째와 네 번째에 있었다. 앞의 두 컬럼은 기간 조건이었고 우리 쿼리에는 그것이 없었다.

복합 인덱스는 왼쪽부터 연속으로 써야 타므로 앞이 비면 뒤의 두 컬럼만으로는 탈 수 없다. 그래서 옵티마이저가 관계없는 인덱스로 물러난 것이었다.

임시 테이블과 파일 정렬

인덱스를 못 타면 정렬 순서도 인덱스에서 얻을 수 없다. 전부 읽어서 따로 정렬하므로 임시 테이블과 파일 정렬이 함께 붙는다.

조건에 맞는 순서로 인덱스를 만들고 정렬과 페이징에 쓰이는 키를 뒤에 붙였다. 다시 실행계획을 보니 훑는 행 수가 줄고 임시 테이블과 파일 정렬이 사라졌다.

무중단 추가와 옵션 명시

운영 테이블이라 인덱스를 추가할 때 알고리즘과 잠금 옵션을 명시했다. 명시하지 않으면 서버가 상황에 따라 테이블 복사와 잠금을 고를 수 있다.

명시해 두면 그 방식이 안 될 때 오류로 끝나고 실행되지 않는다. 운영 중에 몇 분 잠기는 것보다 실행이 안 되는 편이 낫기 때문이다.

이름이 말하지 않는 용도

행 수만 보면 개선이 작아 보였지만 임시 테이블과 파일 정렬이 사라진 것이 실제로 컸다. 실행계획의 행 수는 추정치이므로 그 값만으로 판단하지 않고 부가 정보를 함께 봤다.

기존 인덱스의 이름은 사용 가능한 상품을 뜻하는 것으로 읽혀서 이 조건에 맞는 것처럼 보였다. 실제로는 기간 조건이 있어야 타므로 이름이 용도를 말해 주지 않았고 그 사실을 규칙으로 남겼다.

정리


Share this post on:

Previous Post
묻기 대신 밀어 주기
Next Post
서비스가 둘이면 나가는 길도 둘이다