3

특정 응용 프로그램에 대한 SQL Server의 VARCHAR 대 NVARCHAR에 대한 연구를 통해 SQL Server에서 기본적으로 UTF8을 지원하는 것이 이상적이라는 사실을 알게되었습니다. 여러 SO 게시물은 예를 들어, 그렇지 않은 것을 나타냅니다UTF-8 지원, SQL Server 2012 및 UTF8String UDT

Is VARCHAR like totally 1990s? 그러나

What are the main performance differences between varchar and nvarchar SQL Server data types?

그때 나는 사용자 정의 된 UTF8String에를 만드는 방법을 보여줍니다 SQL 서버 2012에 대한 MSDN 문서에서이 문서를 건너 왔어요 데이터 유형 :

http://msdn.microsoft.com/en-us/library/ff877964(v=sql.110).aspx

하면서 UDT는 공간 (메모리, 디스크) 8 비트 당 문자의 혜택을 허용 할 것으로 보인다 UTF-8로 표현할 수있는 문자열을 저장하기에 충분히 유연합니다. 그 맞습니까? 이 전략의 단점이 있습니까 (예 : 각 행에 대해 관리 코드를 실행하는 데 드는 비용 ...)?

답변

2

SQLCLR을 통해 사용자 정의 사용자 정의 유형을 만들려면 이 아닌입니다. 어떤 식 으로든 기본 유형을 대체 할 것입니다. 특별한 데이터를 처리하기위한 무언가를 만드는 것이 매우 편리합니다. 그러나 문자열은 다른 인코딩의 경우조차도 특수화 된 것이 아닙니다. 문자열 데이터에 대한이 경로를 사용하면 내장 문자열 기능을 사용할 수 없으므로 성능은 말할 것도없고 시스템의 사용 편의성을 파괴 할 수 있습니다.

디스크 공간에 아무 것도 저장할 수 있었다면, 전반적인 성능에서 손실되는 부분에 의해 이러한 이득이 삭제됩니다. UDT를 저장하려면 VARBINARY으로 직렬화하면됩니다. 따라서 문자열 비교 OR 정렬을 수행하려면 "2 진"/ "서수"비교 이외의 다른 모든 값을 하나씩 UTF-8로 변환 한 다음 문자열을 비교해야합니다 언어 적 차이를 설명 할 수있다. 그리고 그 전환은 UDT 내에서 이루어져야 할 것입니다. 즉, XML 데이터 유형과 마찬가지로 특정 값을 보유 할 UDT를 작성한 다음 해당 UDT 메소드에 문자열 매개 변수를 사용하여 비교를 수행 할 수 있습니다 (즉, Utf8String.Compare(alias.field1) 또는 유형에 대한 연산자를 정의한 경우, Utf8string1 = Utf8string2을 입력하고 = 연산자를 사용하여 UTF-8 인코딩으로 문자열을 가져온 다음 CompareInfo.Compare()을 수행하십시오. 위의 사항 외에

, 당신은 또한 특히 (이 혼동하지 마십시오 각각 NVARCHAR(1 - 4000)VARBINARY(1 - 4000)에 반대 NVARCHAR(MAX) 또는 VARBINARY(MAX) 중 하나를 사용하는 경우, 앞뒤로 SQLCLR API를 통해이 통과 값을 고려하는 비용이 필요 사용에 대해 암시하는 구별로 SqlChars/SqlBytesSqlString/SqlBinary).

마지막으로 (적어도 UDT를 사용하여 기준)의 UDT에 대한 샘플 코드이다 물었다되고 있다는 사실을지나 보지 마십시오. 언급 된 유일한 테스트는 순전히 기능적이며, 확장 성 또는 "1 년간이 작업을 통해 얻은 교훈"과 관련이 없습니다.기능 테스트 코드는 다음 CodePlex 페이지에 표시되어 있으며이 결정을 진행하기 전에 쿼리를 작성하여 필드와 상호 작용할 수 있도록 작성해야한다는 느낌을주기 때문에이 결정을 진행해야합니다 (필드 또는 두하지만, 대부분의 하지/모든 문자열 필드) : 계산 열 인덱스가 추가 지속의 수를 감안할 때

http://msftengprodsamples.codeplex.com/SourceControl/latest#Kilimanjaro_Trunk/Programmability/CLR/UTF8String/Scripts/Test.sql

가 어떤 공간이 정말

을 저장 한? ;-)


공간 (디스크, 메모리 등)가 문제이고, 당신은 세 가지 옵션이 있습니다 : 당신은 SQL 서버 2008 이상을 사용하는 경우

  1. , 그리고 엔터프라이즈 에디션에있다 그러면 Data Compression을 사용할 수 있습니다. 데이터 압축은 유니 코드 데이터를 NCHARNVARCHAR 필드로 압축 할 수 있습니다 ("항상"은 아님).

    1. NCHAR(1 - 4000)NVARCHAR(1 - 4000)Standard Compression Scheme for Unicode 사용하지만 SQL Server 2008 R2의 시작, 그리고에서만 행 데이터, 오버 플로우하지 : 결정 요인은! 이것은 일반적인 ROW/PAGE 압축 알고리즘보다 우수합니다. 확실하지 (
    2. NVARCHAR(MAX)XML (LOB 또는 용량 초과 페이지에서하지 오프 행) 행에 데이터 (그리고 나는 또한 VARBINARY(MAX), TEXTNTEXT 추측은) 적어도 PAGE 압축 될 수 있으며, 어쩌면 또한 압축 행 이 마지막 것에 관해서).
    3. OFF ROW 데이터, LOB 또는 OVERLOW = No Compression For You! 하나 VARCHARNVARCHAR :
  2. 2008보다 이전 여부 엔터프라이즈 에디션의 버전을 사용하는 경우

  3. , 당신은 두 개의 필드를 가질 수 있습니다. 예를 들어, 대부분 기본 ASCII 문자 (값 0-127)이고 따라서 VARCHAR에 맞는 URL을 저장한다고 가정 해 보겠습니다. 그러나 때로는 유니 코드 문자가 포함되어 있습니다. [URL] 계산 열에서이 모델 당신 SELECT에서

    ... 
        URLa VARCHAR(2048) NULL, 
        URLu NVARCHAR(2048) NULL, 
        URL AS (ISNULL(CONVERT(NVARCHAR([URLa])), [URLu])), 
        CONSTRAINT [CK_TableName_OneUrlMax] CHECK (
            ([URLa] IS NOT NULL OR [URLu] IS NOT NULL) 
           AND ([URLa] IS NULL OR [URLu] IS NULL)) 
    ); 
    

    : 귀하의 스키마는 다음과 같은 3 개 필드를 포함 할 수 있습니다. 이 필드를 한 경우에만 이제까지에 맞게 문자를해야

    INSERT INTO TableName (..., URLa, URLu) 
    VALUES (..., 
         IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL), 
         IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL) 
         ); 
    
  4. : 삽입 및 업데이트의 경우 달라져에게이 들어오는 값을 변환하는 NVARCHAR 형식이어야하는 경우 확인하여 사용할 필드 결정 확장 ASCII 문자 세트의 특정 코드 페이지는 VARCHAR을 사용하십시오.


P.S.그냥이 명확하게 언급 한합니다 : SQL 서버 2012 년에 도입 된 새로운 _SC 데이터 정렬은 단순히 허용 :

  • 내장 제대로 보충 문자/대리 쌍, 및
  • 언어 규칙을 처리 할 수있는 기능 보충 순서에 사용되는 문자와 비교도 새로운 _SC 데이터 정렬없이

하지만, 위해, 당신은 여전히 ​​XML 또는 N -prefixed 유형에 유니 코드 문자를 저장할 수 있으며, 데이터 손실로를 검색 할 수 있습니다. 그러나 이전 버전의 Collations (이름에 버전 번호 없음)를 사용하면 모든 보조 문자가 서로 동일합니다. _90_100 데이터 정렬/코드 포인트 비교 및 ​​정렬이 필요한 조합을 사용해야합니다. 보충 문자의 특정 매핑이 없으므로 (따라서 가중치 또는 정규화 규칙이 없음) 언어 규칙을 고려할 수 없습니다.

는 다음 시도하십시오 DB에서

IF (N'' = N'') SELECT N'' AS [TheLiteral], NCHAR(150150) AS [Generated]; 
IF (N'' = N'') SELECT N'' AS [TheLiteral], NCHAR(150151) AS [Generated]; 
IF (N'' COLLATE Tatar_90_CI_AI = N'' COLLATE Tatar_90_CI_AI) 
     SELECT N' COLLATE Tatar_90_CI_AI' AS [TheLiteral], NCHAR(150151) AS [Generated]; 
IF (N'' = N'?') SELECT N'?'; 

_SC로 끝나는 기본 데이터 정렬을 가진, 첫 번째 IF 문은 결과 집합을 반환하고, "생성"필드는 문자를 올바르게 표시됩니다. DB를가 기본 데이터 정렬이 _SC로 끝나는, 그리고 정렬이 _90 또는 _100 시리즈 정렬되지 않습니다이없는 경우 "생성"필드가 NULL를 반환합니다 특징

하지만, 다음, 처음 두 IF 문은 결과 집합을 반환 "Literal"필드가 올바르게 표시됩니다.

유니 코드 데이터의 경우 데이터 정렬은 실제 저장소에 영향을 미치지 않습니다.

+0

'NVARCHAR (1 - 4000)'의 의미는 무엇입니까? –

+0

@EricJ. 1에서 4000 사이의 숫자를 선택하는 것을 의미합니다. –

+0

@EricJ. 미안해. 미안. 기본적으로 Aaron이 말했듯이, 이것은 단지 1 - 4000 범위 일 수있는 비 -MAX' NVARCHAR 타입을 나타내는 나의 방법 일뿐입니다. –