MSSQL을 사용할 때
인덱스가 걸려있는 VARCHAR 컬럼데이터를 조회시 NVARCHAR로 데이터를 넘길경우
인덱스가 걸리지 않아 성능에 문제가 발생하는 사례가 존재한다.

(쿼리분석기에서는 빠른데 미들웨어에서 호출 시 느린경우)


 하여 보통은 jtds 드라이버 설정시
 sendStringParametersAsUnicode=false
 값을 주어 유니코드 처리하지 않게 함으로서 VARCHAR로 처리 되도록 하여 해결을 하고 있다.

 근데 문제는
 VARCHAR 와 NVARCHAR 가 섞여있을 경우에는 어떻게 해야 하는가?

 사실 이문제는 아래와 같이 풀면 해결이 될거라고 생각했다.

 1) 드라이버에서는 유니코드를 사용하지 않음 처리.
     - sendStringParametersAsUnicode=false
 2) mybatis mapper 에 jdbcType 을 부여
    - #{column, jdbcType=NVARCHAR}

 혹은 1)번을 부여하지 않고( default 는 sendStringParametersAsUnicode=true 이다. )
 #{column, jdbcType=NVARCHAR} 와 #{column, jdbcType=VARCHAR} 를 명시해주면 되지 않을까?

 라고 생각했었다.

 하지만, 결론은 안된다는거...

 그래서 jtds 드라이버 소스코드를 살펴 보았다.

 역시...NVARCHAR 사용을 위한 setNString() 에서 아래와 같은 코드로 구현이 되어있었고,

  [ JtdsCallableStatement.java ]

  public void setNString(String parameterName, String value)
            throws SQLException {
        // TODO Auto-generated method stub
        throw new AbstractMethodError();
    }

  public void setNString(int parameterIndex, String value)
            throws SQLException {
        // TODO Auto-generated method stub
        throw new AbstractMethodError();
    }

 실제 TdsData.java  ( getNativeType 메소드 ) , Support.java ( getJdbcTypeName 메소드 )내에서 지원가능한 jdbcType 검사를 하는데  여기에도 NVARCHAR 가 누락이 되어있다.

그럼 어떻게 NVARCHAR 를 지원하고 있었던걸까?

결론은 이렇다.

jtds 에서는 모든 NVARCHAR 든 VARCHAR 든 VARCHAR 로 인식하고 드라이버에 설정된 유니코드 사용여부에 따라 VARCHAR를 변환하고 있었던 것이다.

'모' 아니면 '도' 로 말이다.

그렇다면 이부분을 어떻게 해결할 수 있을까?

답은 간단하다.

setNString 구간에 setString 을 참조하여 내용을 체워주고,

JtdsPreparedStatement.java ]
protected void setParameter(int parameterIndex, Object x, int targetSqlType, int scale, int length)

메소드에 NVARCHAR 타입일 경우 pi.isUnicode = true 로 부여하면,

mybatis에서 NVARCHAR 로 jdbcType 을 부여한 것에 대해서 처리가 가능하다.

이때, mybatis 부분도 수정이 필요한데 이유는 이렇다.

mybatis 의 NVARCHAR 를 처리하는 NStringTypeHandler 라는 클래스가 존재하는데

이 클래스에서 파라미터 바인딩시 setString 이 호출되게 되어있다.

이걸 setNString 을 호출하게 변경하면, 정상처리가 되게 되는 것이다.


이번 기회에 jtds 내에서 어떤 일이 일어나는지 알게된 점이 좋았던거 같다.

그리고 왜 NVARCHAR 를 지원하지 않게 되어있는지...그리고 mybatis에서도 왜 NStringTypeHandler 에서도

setNString 이 아니라 setString 으로 되어있었는지에 대해서는 좀더 고민을 해봐야 할듯하다.

이유가 없지는 않을테니 말이다.

여하튼 이렇게 VARCHAR 와 NVARCHAR 을 Mix 에서 사용하는 곳에서는
이런 부분도 고려가 되어야 할듯하다.




출처 : http://ymseok.blogspot.kr/2013/07/jtds-mssql-nvarchar.html

Posted by 파이팅야
,