varchar와 nvarchar의 차이를 알아봅시다.
아래 코드는 테스트에 사용한 테이블을 생성하는 코드입니다.
CREATE TABLE [dbo].[tb_Test_nvarchar](
[id] [int] IDENTITY(1,1) NOT NULL,
[test1] [nvarchar](32) NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[tb_Test_varchar](
[id] [int] IDENTITY(1,1) NOT NULL,
[test2] [varchar](32) NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[tb_Test_varchar64](
[id] [int] IDENTITY(1,1) NOT NULL,
[test3] [varchar](64) NULL
) ON [PRIMARY]
GO
varchar는 가변 문자열
nvarchar을 가변 유니코드 문자열입니다.
다국어 지원을 할 거면 당연히 nvarchar를 사용하여야 합니다.
(nchar, ntext 등등)
그래야 MSSQL에서 UTF-16으로 변환합니다.
(참고 : MS Docs - nchar 및 nvarchar(Transact-SQL) )
이건 유니코드 문자를 입력해보면 확인할 수 있습니다.
--입력
Insert Into tb_Test_nvarchar(test1) Values(N'℅℆⊕⍹⛩');
Insert Into tb_Test_varchar(test2) Values(N'℅℆⊕⍹⛩');
Insert Into tb_Test_varchar64(test3) Values(N'℅℆⊕⍹⛩');
Insert Into tb_Test_nvarchar(test1) Values('水z𝄞');
Insert Into tb_Test_varchar(test2) Values('水z𝄞');
Insert Into tb_Test_varchar64(test3) Values('水z𝄞');
varchar는 영문이나 숫자 등은 1바이트,
한글이나 한자 같은 것들은 2바이트로 저장합니다.
nvarchar의 경우는 어떤 문자든 2바이트로 저장하죠.
varchar의 최대 크기는 8000입니다.
nvarchar는 2배를쓰므로 4000 입니다.
이것을 확인하려면 아래 SQL을 실행해보면 됩니다.
Declare @test1 nvarchar(4001);
-- 에러 : 매개 변수 '@test1'에 지정한 크기(4001)가 최대 허용 크기(4000)를 초과합니다.
Declare @test2 varchar(8001);
-- 에러 : 유형 'varchar'에 지정한 크기(8001)가 모든 데이터 형식의 최대 허용 크기(8000)를 초과합니다.
이제 아래 쿼리를 사용하여 데이터가 어떻게 들어가는지 확인해 봅시다.
Declare @test1 nvarchar(3);
Declare @test2 varchar(3);
Declare @test3 varchar(6);
set @test1 = '가나다';
set @test2 = '가나다';
set @test3 = '가나다';
select @test1, @test2, @test3, LEN(@test1), LEN(@test2), LEN(@test3);
varchar(3)의 경우 한글이 3자가 안 들어가는 것을 알 수 있죠.
그래서 다국어 지원의 경우 nvarchar를 사용해야 합니다.
nvarchar를 호환성은 좋지만, 용량이 크다고 표현합니다.
물리 용량에서도 차이가 난다고 알고 있었는데....
어떻게 테스트해도 물리 용량이 차이나는 걸 확인 할 수 없었습니다.
검색해보면 많은 내용이 물리 용량에서 차이가 난다는데.....
직접 테스트가 되질 않네요.
* 이유는 다음 챕터에 나옵니다. *
테스트한 내용들
exec sp_spaceused tb_Test_nvarchar;
exec sp_spaceused tb_Test_varchar;
exec sp_spaceused tb_Test_varchar64;
혹시나 'sysindexes.reserved'로 계산하면 다른가 해서 해봤습니다.
('sp_spaceused'와 'sysindexes.reserved'는 같은 용량 나오는게 맞습니다.)
SELECT CONVERT(VARCHAR(30), MIN(o.name)) AS t_name
, LTRIM(STR(SUM(reserved) * 8192.0 / 1024.0, 15, 0)) AS t_size
, UNIT = 'KB'
FROM sysindexes i INNER JOIN sysobjects o ON o.id = i.id
WHERE i.indid IN (0, 1, 255) AND o.xtype = 'U'
GROUP BY i.id
ORDER BY t_name ASC
여러 번 테스트하면서 원인을 찾았습니다.
제가 테스트용 데이터를 잘못 넣고 있었네요 ㅎㅎㅎㅎ
한글과 영어를 섞어 넣는다는 게 한글만 넣어서 생기는 문제였습니다.
한글만 넣으면 둘 다 2바이트 처리가 돼서 용량이 똑같아지죠;;;;
이제 제대로 용량 차이가 나네요.
이런 어이없는 실수를 이제야 찾아내다니 ㅎㅎㅎㅎ
이거 테스트하느냐 글을 몇번을 수정한건지 ㅎㅎㅎㅎ