본문 바로가기

트러블슈팅

SQL Server에게 String은 NVARCHAR이다.

결론 먼저

  • SQL Server JDBC Driver 는 String type 의 pamameter 를 기본적으로 NVARCHAR 로 매핑한다는 사실을 반드시 기억하고 사용하자.
  • String type 의 parameter 를 기본 VARCHAR 로 매핑하고 싶다면 또는 해야한다면, JDBC URL 에 sendStringParametersAsUnicode=false 를 추가하자
  • Mybatis의 경우 아래와 같이 cast를 이용해 조회조건에서 String type의 파라미터를 VARCHAR로 바꿔 사용하자.
 select * from varchar 컬럼 = cast('String 파라미터' varchar)

문제점

DB Lock 이슈로 인해 Query 모니터링 중 CPU를 많이 차지하는 SQL Query가 있었습니다.

<select id = "selectBLInfo" parameterClass="HashMap" resultClass="BlInfoVO">
  SELECT BL_NO, BL_STS_CD, OFC_CD 
  FROM TB_BL
  WHERE BL_NO = #bl_no#
</select>

왜 해당 쿼리에서 많은 CPU를 소모하는가 했더니, 주요 INDEX 컬럼이자 조회 컬럼인 BL_NO의 type이 VARCHAR이고 , 파라미터로 받는 #bl_no#는 NVARCHAR였습니다.

위에서 말했듯이 SQL Server JDBC Driver는 String type의 파라미터를 유니코드 타입인 nvarchar(4000) 형식으로 전달합니다. MSSQL의 Data Type의 우선순위에서 NVARCHAR가 VARCHAR보다 높기 때문에 VARCHAR 컬럼에 대한 조회 조건으로 String 파라미터를 사용할 경우, VARCHAR 컬럼이 모두 NVARCHAR로 형변환이 일어난 후 조건을 비교하게 됩니다. 형변환이 일어나기 때문에 VARCHAR 컬럼의 INDEX도 무시됩니다. VARCHAR 컬럼의 데이터를 모두 NVARCHAR로 변환하고, INDEX도 무시되므로, 이로 인해 데이터가 많을수록 그만큼 형변환으로 인한 비용도 많이 들고 성능도 떨어집니다.

TB_BL은 수만 건이 등록되어 있는 테이블이었고, 수만 건의 BL_NO를 모두 NVARCHAR로 변환하고 Index도 무시되면서 많은 CPU가 소모된 것입니다.

 

해결 방법

sendStringParametersAsUnicode=false 추가

아래와 같이 JDBC URL 에 sendStringParametersAsUnicode=false 를 추가합니다.
이 설정 덕분에 앞으로 모든 String 파라미터를 모두 VARCHAR 타입으로 매핑하게 됩니다.

spring:
  datasource:
    type: org.apache.tomcat.jdbc.pool.DataSource
    driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
    url: jdbc:sqlserver://rubyhost:6436;database=SbSvc;sendStringParametersAsUnicode=false

NVARCHAR 파라미터에 Cast 사용

NVARCHAR 파라미터에 CAST를 사용하여 VARCHAR로 변경시켜주면, VARCHAR 끼리 비교이므로 형변환이 일어나지 않습니다.

<select id = "selectBLInfo" parameterClass="HashMap" resultClass="BlInfoVO">
  SELECT BL_NO, BL_STS_CD, OFC_CD 
  FROM TB_BL
  WHERE BL_NO = CAST(#bl_no# AS VARCHAR) 
</select>

 

VARCHAR, NVARCHAR 차이

VARCHAR는 가변 문자열, NVARCHAR를 가변 유니코드 문자열 입니다.

 

VARCHAR

  • 일반적으로 사용하는 문자열 Data type 입니다.
  • VARCHAR는 유니 코드가 아닌 ASCII 데이터를 저장합니다.
  • VARCHAR는 문자 당 1 바이트를 사용, 한글은 2바이트 사용합니다.
  • 데이터베이스에 각 문자열의 길이를 저장합니다.
  • VARCHAR는 가변 데이터 길이를 가지며 최대 8000개의 비 유니 코드 문자를 저장합니다.
  • VARCHAR는 유니 코드가 아닌 문자가있는 변수가있는 곳에서 사용하는 것이 좋습니다.

NVARCHAR

  • NVARCHAR는 유니 코드 문자를 저장
  • 따라서, 다국어 지원을 하려면 NVARCHAR를 사용해야 합니다.
  • NVARCHAR는 문자 당 2 바이트를 사용합니다.
  • NVARCHAR는 최대 4000 개의 유니 코드 또는 비 유니 코드 문자를 저장합니다.
  • NVARCHAR는 유니 코드 문자가있는 변수가있는 곳에서 사용됩니다.

참조

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