쿼리 실행 계획이 조건값에 따라 변경되는데 예측할 수 있는 방법이 있을까요? 0 4 640

by et_cetera [MySQL] [2020.01.16 19:04:24]


최근에 MySQL에서 쿼리를 아래처럼 oder by 조건만 수정했는데 특정 사용자에 대해서만 인덱스가 다르게 타면서 쿼리가 갑자기 느려지는 증상이 나타나서 문의드립니다.

 

수정한 부분은 "INSERT_DT" 필드가 인덱스가 잡혀있지 않아서 성능 개선을 위해 인덱스가 잡힌 "REG_DT"로 order by를 변경한 것 뿐입니다.

테이블에 인덱스는 IDX01 (USER_ID), IDX02 (REG_DT) 이렇게 각각 잡혀 있습니다.

대부분의 사용자가 IDX01를 먼저 타고 IDX02를 타서 조회되는 모수가 줄어드는데, 특정 사용자들이 IDX02를 먼저 타고 IDX01을 타는 바람에 불필요한 데이터를 대량 조회하면서 쿼리 수행 시간이 급격히 늘어났습니다.

 

이런 문제가 어떤 원인으로 인해 갑자기 생길 수 있으며, 이를 쿼리 수정 및 테스트를 하면서 사전에 감지할 수 있는 방법이 없을까요?

쿼리 수정 전에 explain으로 실행 계획을 확인해볼 때 아무래도 사용자가 많다보니 모든 사용자를 확인하지 못하고 일부 사용자만 확인을 한 후에 실행 계획이 동일한 것으로 확인하고 적용했는데 이런 문제가 생기니 당황스럽습니다.

-- 수정전
SELECT	*
FROM	TB_HISTORY
WHERE	USER_ID = 'abc123'
AND		REG_DT BETWEEN DATE_SUB(NOW(), INTERVAL 3 MONTH) AND NOW() 
ORDER BY INSERT_DT DESC
LIMIT 10;

 

-- 수정 후
SELECT	*
FROM	TB_HISTORY
WHERE	USER_ID = 'abc123'
AND		REG_DT BETWEEN DATE_SUB(NOW(), INTERVAL 3 MONTH) AND NOW() 
ORDER BY REG_DT DESC
LIMIT 10;

 

by 마농 [2020.01.17 07:38:16]

보통 1개 인덱스만 이용되지 않나요?
2개 인덱스가 동시 이용되지는 않을 텐데요?
해당 쿼리에 적합한 인덱스는 (user_id + reg_dt) 결합인덱스입니다.


by et_cetera [2020.01.17 10:03:56]

답변 감사합니다.

말씀해주신대로 인덱스 생성이 테이블 주요 사용 목적에 맞게 생성되지 않아서 생기는 문제라서 말씀해주신 인덱스를 생성할 계획을 잡고 있긴 합니다.

또한 인덱스가 하나만 선택되어 적용되는 걸로 봐서 개발시 유의를 해야 겠습니다. 


by jkson [2020.01.17 08:10:23]

user_id 조건은 바인드변수가 아닌가보죠?

사용자에 따라 해당 사용자의 데이터를 찾고 sort하는 것보다 reg_dt로 desc sort하고 해당 사용자를 필터하는 게 낫다고 판단했다면 그럴 수 있을 것 같은데요.

실제 성능상 이점이 없다면 힌트로 실행계획을 고정하든지, user_id 조건을 바인드변수로 받아 실행계획이 분기되지 않게 해야할 것 같습니다.

user_id 인덱스에 reg_dt를 추가하시면 옵티마이저가 결합인덱스를 우선으로 고려하겠네요.


by et_cetera [2020.01.17 10:16:58]

답변 감사합니다.

당장 테이블의 인덱스를 추가하는게 아무래도 부담이 되다보니 말씀해주신대로 힌트를 줘서 테스트해보고 적용하려고 합니다.

제가 인덱스를 너무 생각없이 만들어서 무지 반성하고 있습니다.

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입