급여 테이블에서 현재 유효한 급여 정보만 조회하고자 사용여부 컬럼의 값이 1인 데이터를 출력하는 쿼리가 있다고 하자.
튜닝 전 실행 계획은 다음과 같다.
type
항목이 index이므로 인덱스 풀 스캔 방식으로 수행하되,Key
항목의 I\_사용여부
인덱스를 사용함을 알 수 있다.
또한 filtered
항목이 10.00이므로 스토리지 엔진에서 가져온 데이터 중 10%를 추출해서 최종 데이터를 출력할 것임을 알 수 있다(단, filtered 항목의 값은 정확히 10%가 아니라 통계 정보로부터 예측된 값임을 주의한다).
먼저 사용여부 컬럼의 데이터 건수를 확인해 보자. 해당 컬럼은 0, 1로 이루어져있음을 확인할 수 있다.
이번에는 해당 테이블에 구성된 인덱스 현황을 살펴보자.
Key_name 항목에 튜닝 전 실행 계획에 나왔던 I_사용여부 인덱스가 있다. 해당 인덱스는 사용여부
컬럼으로 구성된다.
SQL 문에서 사용여부
컬럼이 인덱스로 구성되었고, WHERE 절의 조건문으로 작성되었음에도 불구하고 인덱스 풀 스캔으로 수행되는 이유는 무엇일까? 이를 확인하기 위해 테이블 구조를 다시 살펴봐야 한다.
사용여부 컬럼의 데이터 유형이 문자열임을 알 수 있다. 따라서, 튜닝 전 SQL 문의 WHERE 절은 사용여부 = 1
과 같이 숫자 유형으로 써서 데이터에 접근했으므로, DBMS 내부에서 형변환이 발생했던 것이다. 그 결과 인덱스를 제대로 활용하지 못하고 전체 데이터를 스캔한 것이다. 따라서 형변환이 발생하지 않도록 SQL 문을 조정해야 한다.
형변환을 제거한 SQL문과 그 실행 결과는 다음과 같다. 실행 시간은 1.76초
에서 0.03초
로 향상되었다.
튜닝 후 실행 계획을 살펴보면, 튜닝 전과 달리 사용여부 = '1'
조건절이 스토리지 엔진에서 전달되어 필요한 데이터만 가져왔음을 알 수 있다.
위 문제를 해결하는 또 다른 방법으로는 사용여부
컬럼의 데이터 유형을 변경하는 방법이 있다. CHAR(1)에서 INT로 변경하기만 하면 SQL 문을 수정하지 않고도 그대로 인덱스를 사용할 수 있다. 그러나 테이블의 DDL 문을 수행해야 하는 부담과 DDL 수행 시의 데이터 잠김(data lock) 현상으로 인해 동시성 저하 문제가 발생할 수 있다.
위 사례를 통해 데이터 유형에 맞게 컬럼을 활용해야 내부적인 형변환이 발생하지 않으며, 형변환의 영향으로 의도한 인덱스를 제대로 사용하지 못할 수 있음을 기억하자.