보통은 회사에서 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/
'Java > Spring' 카테고리의 다른 글
WebClient Request, Response 통신데이터 확인하기 (1) | 2023.11.27 |
---|---|
Spring Boot, JPA로 만든 API 서비스의 성능 개선하기 (0) | 2023.05.08 |
JPA을 이용하여 복합키 테이블에 데이터 삽입시 select insert 방지하기 (0) | 2023.05.08 |
댓글