본문 바로가기
Java/Spring

JPA로 mssql(sql server)의 문자열 데이터 조회할 때 인덱스 적용 안됨 이슈

by 크라크라 2023. 4. 20.

 보통은 회사에서 JPA를 사용한다고 하시면 오라클을 많이 사용하시겠지만, 상황에 따라서는 MS-SQL (SQL Server) 도 많이 사용할 것입니다. 그런데, MS-SQL 에 JPA를 연동해서 사용하실 때 성능 이슈를 조심할 부분이 있습니다. 

 

 테이블에 인덱스를 걸어두었는데, 실제로는 제대로 동작을 하고 있지 않는 케이스가 발생하는 것이죠. 

실제로 데이터베이스에서 문자를 저장하는 방법은 다양하고, 일반적으로 문자 데이터는 MS-SQL에서 주로 varcahr, nvarchar 를 사용을 합니다. 그런데, JPA에서는 이것을 String 으로 통일해서 사용하고 있습니다. 이 말은 JPA가 내부적으로 데이터베이스의 특정한 타입을 변경을 해준다는 것인데 그 과정에서 인덱스가 제대로 적용되지 않을 수 있습니다. 

 

 

 일반적으로 단순 숫자나 영문으로만 구성된 데이터의 경우에는 유니코드 저장이 불필요하기 때문에  varchar 나 char 로 정의해서 사용을 하는 케이스가 많을 것입니다.  그런데 이렇게 varchar 나 char로 되어있는 테이블 컬럼에 인덱스를 걸어둔 상태에서 JPA를 통해서 데이터를 조회해보면 이상하게 풀스캔을 하게 됩니다.

 

왜 인덱스를 걸어두었는데도 풀스캔을 하고 있을까요? 실제로 데이터베이스 프로파일러를 통해서 호출하는 쿼리를 확인해보면, JPA로 쿼리를 호출하는 경우에는 모두 nvarchar와 nchar로 간주되고 있습니다.

 

이 경우에는 인덱스를 타지 않습니다. 

 

실제 실행계획을 통해서 확인해볼 수 있습니다.

아래의 그림은  약 50만건에 대해서 실행계획을 떠본 것입니다.

이 중에서 "읽은 행수"와 "모든 실행에 대한 실제 행수"를 확인해보면 실제 데이터베이스가 쿼리를 실행하면서 얼마나 많은 행을 읽었는지를 볼 수 있습니다. 

 

왼쪽은 제가 인덱스의 모든 컬럼들을 nvarchar로 바꿔서 실행계획을 확인한 것이고, 오른쪽은 인덱스의 모든 컬럼이 varchar로 되어있는 문제 상황의 경우입니다. 

 

확인해보면 실제 행 수는 2건이죠. 이 때,  왼쪽에서는 읽은 행 수가  2건인데 오른 족에서는 읽은 행수가 542251건입니다. 

 

 

 

 실제 서비스 오픈을 위한 부하테스트를 하다가, 조인이 없는 테이블이 데이터만 많다고해서 거의 1초가까이 걸리는 상황을 발견해서 찾아본 것인데요. 초 간단 해결책은 JPA에서 사용하는 기본값인 nvarchar로 컬럼 설정을 맞춰주면 됩니다. 

적용한 이후에 다시 테스트해보니 최소로 1.5배 ~ 2배 정도로 조회 성능이 개선되는 것을 확인할 수 있었습니다. 

 

이와 같은 이슈로 작성된 다른 글들도 참고해보시기 바랍니다. 아래는 배민에서 작성한 글입니다

https://techblog.woowahan.com/2605/

 

 

댓글