SQL Server
묵시적형변환 데이터 형식 우선 순위 int <-> varchar 사이 varchar <-> nvarchar 사이
미스터몽키
2019. 2. 2. 12:08
그동안은 사용하지 않던 유니코드 타입 nvarchar 타입을 사용해야만 해서 이 글을 작성하게 되었다.
한국어가 아닌 글로벌 언어에서 사용되어야 해서...
그동안 한국에서만 사용되는 프로그램을 개발하다보니 데이터 정렬 collation 을 Korean_Wansung_CI_AS 로 설정하고 문자열을 char 또는 varchar 로 사용했다.
데이터 공간도 절약하고 SMS 문자 전송 등에서 byte 단위로 문자를 계산하므로 숫자, 영어는 1바이트 한글은 2바이트로 계산하는 char, varchar 를 사용했다.
유니코드 타입 nvarchar 타입은 숫자, 영문, 한글 모두 2바이트로 저장한다.
nvarchar 타입이 숫자, 영문, 한글 모두 같은 방식으로 계산하므로 편리한 면은 있지만 아직 Ansi 체계를 벗어나지 못한 환경이 많으므로 필요에 따라 선택해야 한다.
그도안 nchar 나 nvarchar를 외면한 가장 큰 이유는 저장공간이 더 차지하는 것 보다 varchar 를 nvarchar로 전환했을 때 쿼리문 작성에서 문자열 상수 앞에 영문 대문자 N을 붙여야하는 부분이다.
지저분하게 무언가를 붙이는 것이 너무 싫었다.
그래서 그동안 한국어만 사용되는 프로그램은 Korean_Wansung_CI_AS 데이터정렬에 char, varchar 타입을 사용했다.
그러나 글로벌 언어 이슈로 인해 어쩔수 없이 nvarchar 타입을 사용해야해서 문자열 상수 앞에 N을 안 붙일 방법이 있는지 확인하게되었다.
결국 방법이 있다는 것을 알았고 그것은 바로 묵시적(암시적) 형변환 이다.
테스트를 위해 그림과 같은 테이블 4개를 만든다. COL1 이 모두 PK 이다.
사전지식으로 숫자와 문자열 사이의 데이터 형식 우선순위는 숫자 int 가 문자열 varchar 보다 더 높다는 것을 알아야한다.
(참고) 데이터 형식 우선순위
우선 숫자와 문자열 사이의 묵시적 형변환 우선 순위를 알아보자
다음의 두 쿼리는 둘다 에러 없이 실행되고 인덱스를 사용한다.
(쿼리1-1)
SELECT * FROM T1
WHERE COL1 = '1'
(쿼리1-2)
SELECT * FROM T2
WHERE COL1 = '1'
-- (쿼리1-1) 은 좌변 숫자타입 int 가 우변 문자열 상수 varchar 보다 데이터 형식 우선 순위가 높아서
varchar 가 int로 묵시적 형변환 하게 된다.
(쿼리1-2)는 문자열타입 컬럼에 문자열상수 이므로 거론할 여지가 없다.
결국 둘다 인덱스를 사용하게 되는 굿~ 한 상황이다.
그러나 다음의 두 쿼리는 비록 에러 없이 실행되더라도 비용이 다르다.
(쿼리2-1)
SELECT * FROM T1
WHERE COL1 = 1
(쿼리2-2)
SELECT * FROM T2
WHERE COL1 = 1
-- (쿼리2-1) 은 거론할 필요가 없고, (쿼리2-2) 는 좌변 문자열 타입 varchar 가 우변 숫자 상수 int 보다 데이터 형식 우선 순위가 낮으므로 좌변이 묵시적으로 int 로 형변환하게 된다.
where 절에서 좌변이 바뀌므로 인덱스는 사용되지 않고 풀 스캔 하게 되어 비용이 많이 들게 된다.
위의 숫자 int 와 문자열 varchar 타입의 묵시적 형변환 관계를 이해했다면
varchar 타입과 nvarchar 타입의 묵시적 형변환도 예상할 수 있다.
참고로 nvarchar 이 varchar 보다 우선 순위가 높다.
다음의 두 쿼리는 인덱스를 사용한다.
(쿼리3-1)
SELECT * FROM T3
WHERE COL1 LIKE '김%'
(쿼리3-2)
SELECT * FROM T4
WHERE COL1 LIKE '김%'
-- (쿼리3-2)에서 COL1 컬럼 nvarchar 타입이 우변 문자열 상수 varchar 타입보다 우선 순위가 높아 우변이 묵시적으로 형변환하게 되어 인덱스를 사용하게 된다. 베리 굿~
그러나 다음의 쿼리는 다르다.
(쿼리4-1)
SELECT * FROM T3
WHERE COL1 LIKE N'김%'
(쿼리4-2)
SELECT * FROM T4
WHERE COL1 LIKE N'김%'
둘다 에러없이 조회는 되더라도 (쿼리4-1)은 좌변이 형변환하게되어 풀 스캔하여 인덱스를 사용 안하고 비용이 더 든다. 물론 varchar 타입에 N을 붙여서 조회하지는 않겠지만...
(쿼리4-2) 정상적으로 nvarchar 타입일때 문자열상수앞에 N을 붙였으니 명시적으로 작성된 쿼리문이다.
결국 유니코드 타입 nvarchar 으로 컬럼을 설정해도 조건절에서 문자열 상수 앞에 N을 안 붙여도 된다.
물론 nvarchar 타입일 때는 문자열 상수 앞에 N을 붙이는 것이 명시적으로 정확하다.
이외 혹시 다른 상황이 있을 수는 있겠지만 현재까지는 기존에 하듯이 N 없이 쿼리문을 작성하면 될 것 같다.