문제

저는 학교에서 다음을 사용하여 소규모 웹 앱용 데이터베이스를 작업하고 있습니다. SQL Server 2005.
나는 문제에 관한 몇 가지 생각의 학교를 봅니다. varcharnvarchar:

  1. 사용 varchar 많은 국제화 데이터를 다루지 않는 한 다음을 사용하십시오. nvarchar.
  2. 그냥 사용 nvarchar 모두를위한.

이제 View 2의 장점이 보이기 시작했습니다.nvarchar가 두 배의 공간을 차지한다는 것을 알고 있지만 이는 수백 명의 학생에 대한 데이터만 저장하기 때문에 반드시 큰 문제는 아닙니다.나에게는 그것에 대해 걱정하지 않고 모든 것이 nvarchar를 사용하도록 허용하는 것이 가장 쉬운 것 같습니다.아니면 내가 놓친 것이 있습니까?

도움이 되었습니까?

해결책

항상 nvarchar를 사용하십시오.

대부분의 응용 프로그램에서는 더블바이트 문자가 필요하지 않을 수도 있습니다.그러나 더블바이트 언어를 지원해야 하고 데이터베이스 스키마에 싱글바이트만 지원하는 경우 돌아가서 애플리케이션 전체를 수정하는 데 비용이 많이 듭니다.

하나의 응용 프로그램을 varchar에서 nvarchar로 마이그레이션하는 데 드는 비용은 대부분의 응용 프로그램에서 사용하게 될 약간의 추가 디스크 공간보다 훨씬 높습니다.

다른 팁

디스크 공간이 문제가 아닌데...하지만 메모리와 성능은 그럴 것입니다.페이지 읽기 두 배, 인덱스 크기 두 배, 이상한 LIKE 및 = 상수 동작 등

중국어 등의 스크립트를 저장해야 합니까?예 혹은 아니오...

그리고 MS BOL에서 "유니코드의 저장 및 성능 효과"

편집하다:

nvarchar 성능이 얼마나 나쁠 수 있는지를 강조하는 최근 SO 질문입니다.

SQL Server는 nvarchar 문자열 내부를 검색할 때 높은 CPU를 사용합니다.

일관성을 유지하세요!VARCHAR을 NVARCHAR에 JOIN하면 성능이 크게 저하됩니다.

nvarchar는 메모리, 저장소, 작업 세트 및 인덱싱에 상당한 오버헤드를 발생시키므로 사양에 따라 실제로 그렇게 될 것입니다. 절대 필요하다면 귀찮게 하지 마세요.

엄격하고 빠른 "항상 nvarchar" 규칙은 많은 상황(특히 ASCII/EBCDIC의 ETL 또는 종종 키와 외래 키인 식별자 및 코드 열)에서 완전한 낭비가 될 수 있기 때문에 필요하지 않습니다.

반면에 열의 경우에는 이 질문을 일찍 물어보고 즉시 명확하고 빠른 답변을 얻지 못하면 열을 nvarchar로 만드는 경우가 많습니다.

애플리케이션의 경우 데이터베이스 크기가 작기 때문에 nvarchar가 적합합니다."항상 nvarchar를 사용한다"고 말하는 것은 지나치게 단순화된 것입니다.한자나 기타 이상한 문자를 저장할 필요가 없다면 VARCHAR을 사용하세요. 훨씬 적은 공간을 사용하게 됩니다.현재 직장의 전임자는 필요하지 않을 때 NVARCHAR을 사용하여 무언가를 설계했습니다.최근에 이를 VARCHAR로 전환하여 해당 테이블에서만 15GB를 절약했습니다(고도로 기록되었습니다).또한 해당 테이블에 인덱스가 있고 해당 열을 포함하거나 복합 인덱스를 만들고 싶다면 인덱스 파일 크기를 더 크게 만든 것입니다.

신중하게 결정하세요.SQL 개발 및 데이터 정의에서는 "기본 답변"이 거의 없는 것 같습니다(물론 어떤 대가를 치르더라도 커서를 피하는 것 외에는).

이미 꽤 많은 답변이 있기 때문에 여기에 또 다른 답변을 추가하는 것을 주저하지만, 아직 작성되지 않았거나 명확하게 작성되지 않은 몇 가지 사항을 작성해야 합니다.

첫 번째: 하다 ~ 아니다 항상 사용 NVARCHAR.이는 매우 위험하고 종종 비용이 많이 드는 태도/접근 방식입니다.그리고 "라고 말하는 것이 더 낫지 않습니다.절대 커서 사용"은 때로는 특정 문제를 해결하는 가장 효율적인 수단이고 일반적인 해결 방법이기 때문입니다. WHILE 루프는 거의 항상 a보다 느립니다. 제대로 커서.

"항상"이라는 용어를 사용해야 하는 유일한 경우는 "항상 상황에 가장 적합한 것을 하라"고 조언할 때입니다.물론, 특히 개발 시간의 단기 이익 균형을 맞추려고 할 때 결정하기 어려운 경우가 많습니다(관리자:"지금까지 몰랐던 이 기능이 일주일 전에 필요합니다!") 장기 유지 관리 비용(처음에는 팀에게 3주 스프린트로 3개월 프로젝트를 완료하도록 압력을 가한 관리자) :"왜 이런 성능 문제가 발생하는 걸까요?유연성이 없는 X를 어떻게 할 수 있었을까요?우리는 이 문제를 해결하기 위해 한두 번 질주할 여유가 없습니다.우선순위 항목으로 돌아갈 수 있도록 일주일 안에 무엇을 할 수 있습니까?그리고 이런 일이 계속 발생하지 않도록 디자인에 더 많은 시간을 투자해야 합니다!").

두번째: @gbn의 답변은 경로가 100% 명확하지 않을 때 특정 데이터 모델링 결정을 내릴 때 고려해야 할 몇 가지 매우 중요한 사항을 다룹니다.하지만 고려해야 할 사항이 더 있습니다.

  • 트랜잭션 로그 파일의 크기
  • 복제하는 데 걸리는 시간(복제를 사용하는 경우)
  • ETL에 걸리는 시간(ETLing인 경우)
  • 원격 시스템에 로그를 전달하고 복원하는 데 걸리는 시간(로그 전달을 사용하는 경우)
  • 백업 크기
  • 백업을 완료하는 데 걸리는 시간
  • 복원을 수행하는 데 걸리는 시간(이것은 언젠가 중요할 수 있습니다 ;-)
  • tempdb에 필요한 크기
  • 트리거 성능(tempdb에 저장된 삽입 및 삭제된 테이블의 경우)
  • 행 버전 관리 성능(SNAPSHOT ISOLATION을 사용하는 경우 버전 저장소가 tempdb에 있으므로)
  • CFO가 작년에 SAN에 100만 달러를 지출했기 때문에 추가 스토리지에 25만 달러를 더 승인하지 않겠다고 말했을 때 새 디스크 공간 확보 능력
  • INSERT 및 UPDATE 작업을 수행하는 데 걸리는 시간
  • 인덱스 유지 관리에 소요되는 시간
  • 기타 등등 등등

낭비되는 공간에는 거대한 전체 시스템에 대한 계단식 효과.나는 이 주제에 대해 명시적으로 자세히 설명하는 기사를 썼습니다. 디스크는 싸다!오를리? (무료 등록이 필요합니다.죄송합니다. 저는 해당 정책을 통제할 수 없습니다.)

제삼: 일부 답변은 "이것은 작은 앱입니다"라는 측면에 잘못 초점을 맞추고 있으며 일부 답변은 "적절한 것을 사용하라"고 올바르게 제안하고 있지만 답변 중 어느 것도 O.P.에 대한 실제 지침을 제공하지 못했습니다.질문에 언급된 중요한 세부 사항은 이것이 학교의 웹 페이지라는 것입니다.엄청난!따라서 우리는 다음과 같이 제안할 수 있습니다.

  • 학생 및/또는 교수진 이름 필드는 다음과 같습니다. 아마 BE NVARCHAR 왜냐하면 시간이 지나면서 다른 문화권의 이름이 그 장소에 나타날 가능성이 점점 더 높아지기 때문입니다.
  • 하지만 거리 주소와 도시 이름은요?앱의 목적은 명시되지 않았지만(도움이 되었을 것임) 주소 기록이 있는 경우 특정 지리적 지역(예:단일 언어/문화)를 사용하고 VARCHAR 해당 코드 페이지(필드의 데이터 정렬에서 결정됨)를 사용합니다.
  • 주 및/또는 국가 ISO 코드를 저장하는 경우(저장할 필요 없음) INT / TINYINT ISO 코드는 길이가 고정되어 있고 사람이 읽을 수 있으며 표준이므로 :) 사용 CHAR(2) 두 문자 코드의 경우 CHAR(3) 3자리 코드를 사용하는 경우.그리고 다음과 같은 이진 데이터 정렬 사용을 고려해보세요. Latin1_General_100_BIN2.
  • 우편번호를 저장하는 경우(예:우편번호), 사용 VARCHAR A-Z 이외의 문자는 절대 사용하지 않는 것이 국제 표준이기 때문입니다.그리고 네, 아직도 사용하고 있어요 VARCHAR 우편번호는 숫자가 아니기 때문에 INT가 아닌 미국 우편번호만 저장하더라도 문자열이고 일부는 앞에 "0"이 붙습니다.그리고 다음과 같은 이진 데이터 정렬 사용을 고려해보세요. Latin1_General_100_BIN2.
  • 이메일 주소 및/또는 URL을 저장하는 경우 NVARCHAR 이제 둘 다 유니코드 문자를 포함할 수 있기 때문입니다.
  • 등등....

네번째: 이제 당신은 NVARCHAR 데이터는 잘 맞는 데이터에 필요한 것보다 두 배 더 많은 공간을 차지합니다. VARCHAR ("잘 맞음" = "?"로 바뀌지 않음) 마치 마술처럼 응용 프로그램이 성장했고 이제 이러한 필드 중 하나 이상에 수백만 개의 레코드가 있습니다. 최대 행은 표준 ASCII이지만 일부는 유니코드 문자를 포함하므로 유지해야 합니다. NVARCHAR, 다음을 고려하세요:

  1. SQL Server 2008 - 2016 RTM을 사용하는 경우 그리고 Enterprise Edition에 있거나 SQL Server 2016 SP1(모든 버전에서 데이터 압축을 사용할 수 있음) 이상을 사용하는 경우 활성화할 수 있습니다. 데이터 압축.데이터 압축은 유니코드 데이터를 압축할 수 있지만 "항상"은 아닙니다. NCHAR 그리고 NVARCHAR 필드.결정 요인은 다음과 같습니다.

    1. NCHAR(1 - 4000) 그리고 NVARCHAR(1 - 4000) 사용 유니코드용 표준 압축 방식, 그러나 SQL Server 2008 R2부터 시작하고 OVERFLOW가 아닌 IN ROW 데이터에만 해당됩니다!이는 일반적인 ROW/PAGE 압축 알고리즘보다 나은 것으로 보입니다.
    2. NVARCHAR(MAX) 그리고 XML (그리고 내 생각에도 VARBINARY(MAX), TEXT, 그리고 NTEXT) IN ROW(LOB 또는 OVERFLOW 페이지의 행 외부가 아님)인 데이터는 최소한 PAGE 압축될 수 있지만 ~ 아니다 ROW가 압축되었습니다.물론 PAGE 압축은 행 내부 값의 크기에 따라 달라집니다.VARCHAR(MAX)로 테스트한 결과 6000자/바이트 행은 압축되지 않지만 4000자/바이트 행은 압축되는 것으로 나타났습니다.
    3. OFF ROW 데이터, LOB 또는 OVERLOW = 압축 없음!
  2. SQL Server 2005 또는 2008~2016 RTM을 사용하는 경우 ~ 아니다 Enterprise Edition에서는 다음 두 가지 필드를 가질 수 있습니다.하나 VARCHAR 그리고 하나 NVARCHAR.예를 들어, 대부분 기본 ASCII 문자(값 0 - 127)로 구성된 URL을 저장한다고 가정해 보겠습니다. VARCHAR, 이지만 유니코드 문자가 있는 경우도 있습니다.스키마에는 다음 3개 필드가 포함될 수 있습니다.

      ...
      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))
    );
    

    이 모델에서는 오직 다음에서 선택하세요. [URL] 계산된 열입니다.삽입 및 업데이트의 경우 변환으로 인해 들어오는 값이 변경되는지 확인하여 사용할 필드를 결정합니다. NVARCHAR 유형:

    INSERT INTO TableName (..., URLa, URLu)
    VALUES (...,
            IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
            IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
           );
    
  3. 들어오는 값을 GZIP으로 처리할 수 있습니다. VARBINARY(MAX) 그리고 나가는 길에 압축을 푼다.

    • SQL Server 2005 - 2014의 경우:SQLCLR을 사용할 수 있습니다. SQL# (내가 작성한 SQLCLR 라이브러리)는 다음과 같이 제공됩니다. Util_GZip 그리고 Util_GUnzip 무료 버전에서는
    • SQL Server 2016 이상:내장된 것을 사용할 수 있습니다 COMPRESS 그리고 DECOMPRESS GZip이기도 한 함수입니다.
  4. SQL Server 2017 이상을 사용하는 경우 테이블을 Clustered Columnstore 인덱스로 만드는 방법을 살펴볼 수 있습니다.

  5. 아직 실행 가능한 옵션은 아니지만 SQL Server 2019에서는 UTF-8에 대한 기본 지원을 도입했습니다. VARCHAR / CHAR 데이터 유형.현재 사용하기에는 버그가 너무 많지만 수정된 경우 다음을 위한 옵션입니다. 일부 시나리오.제 글을 봐주세요"SQL Server 2019의 기본 UTF-8 지원:구원자인가 거짓 선지자인가?"에서 이 새로운 기능에 대한 자세한 분석을 확인하세요.

응용 프로그램이 작기 때문에 varchar 대신 nvarchar를 사용하는 경우 기본적으로 비용이 크게 증가하지 않으며 유니코드 데이터를 저장해야 하는 경우 잠재적인 문제를 피할 수 있습니다.

일반적으로 말하면;제약이 가장 적고 가장 비용이 많이 드는 데이터 유형으로 시작하십시오. 생산에 투입.성능이 문제가 되기 시작하면 해당 파일에 실제로 무엇이 저장되어 있는지 알아보세요. nvarchar 열.거기에 맞지 않는 캐릭터가 있습니까? varchar?그렇지 않은 경우 varchar로 전환하십시오.문제가 있는 부분을 알기 전에 사전 최적화를 시도하지 마십시오.내 추측은 nvarchar/varchar 중에서 선택한다고 해서 애플리케이션 속도가 느려지는 것은 아닙니다. 가까운 미래에.성능 조정을 통해 훨씬 더 많은 것을 얻을 수 있는 애플리케이션의 다른 부분이 있을 것입니다. 돈을 위해 쾅.

지난 몇 년 동안 우리 프로젝트는 모두 다국어이기 때문에 모든 프로젝트에 NVARCHAR을 사용해 왔습니다.외부 소스에서 가져온 데이터(예:ASCII 파일 등)은 데이터베이스에 삽입되기 전에 유니코드로 상향 변환됩니다.

아직 더 큰 인덱스 등에서 성능 관련 문제가 발생하지 않았습니다.인덱스는 더 많은 메모리를 사용하지만 메모리는 저렴합니다.

저장 프로시저를 사용하든 SQL을 즉시 구성하든 모든 문자열 상수 앞에 N이 붙어 있는지 확인하세요(예:SET @foo = N'Hello world.';) 따라서 상수도 유니코드입니다.이렇게 하면 런타임 시 문자열 유형 변환이 방지됩니다.

YMMV.

나는 이것에 대해 경험을 통해 말할 수 있습니다. nvarchar.꼭 필요한 경우가 아니면 이 데이터 필드 유형은 대규모 데이터베이스의 성능을 저하시킵니다.성능과 공간 측면에서 취약한 데이터베이스를 물려받았습니다.30GB 데이터베이스의 크기를 70% 줄일 수 있었습니다!성능에 도움이 되도록 몇 가지 다른 수정 사항이 있었지만 나는 확신합니다. varchar그것도 크게 도움이 됐어요.데이터베이스가 테이블을 백만 개 이상으로 늘릴 수 있는 잠재력을 갖고 있다면 nvarchar 모든 수단을 동원하여.

저는 직장에서 다음과 같은 질문을 자주 받습니다.

  • 재고 및 가격의 FTP 피드 - varchar가 제대로 작동했을 때 항목 설명 및 기타 텍스트는 nvarchar에 있었습니다.이를 varchar로 변환하면 파일 크기가 거의 절반으로 줄어들고 업로드에 큰 도움이 되었습니다.

  • 위의 시나리오는 누군가가 항목 설명에 특수 문자를 넣기 전까지는 잘 작동했습니다(상표일 수도 있고 기억이 나지 않음).

나는 여전히 varchar를 통해 매번 nvarchar를 사용하지 않습니다.특수 문자에 대한 의심이나 가능성이 있는 경우 nvarchar를 사용합니다.나는 필드를 채우는 것을 100% 제어할 때 주로 varchar를 사용한다는 것을 알았습니다.

왜 이 모든 논의에서 UTF-8에 대한 언급이 없습니까?문자의 전체 유니코드 범위를 저장할 수 있다고 해서 항상 문자당 2바이트(또는 유니코드 용어를 사용하는 경우 "코드 포인트")를 할당해야 한다는 의미는 아닙니다.ASCII는 모두 UTF-8입니다.SQL Server는 텍스트가 엄격한 ASCII(예:최상위 바이트 비트 0)?나는 그렇지 않기를 바란다.

그렇다면 유니코드를 저장하고 싶다면 그리고 이전 ASCII 전용 응용 프로그램과의 호환성을 원한다면 VARCHAR() 및 UTF-8을 사용하는 것이 마법의 총알이 될 것이라고 생각합니다.필요할 때만 더 많은 공간을 사용합니다.

UTF-8에 익숙하지 않은 분들을 위해 추천해 드릴 수도 있습니다. 입문서.

이를 보장하기 위해 의도적으로 데이터 유형을 제한하려는 예외적인 경우가 있습니다. 그렇지 않다 특정 세트의 문자를 포함합니다.예를 들어 도메인 이름을 데이터베이스에 저장해야 하는 시나리오가 있었습니다.당시 도메인 이름의 국제화는 신뢰할 수 없었기 때문에 기본 수준에서 입력을 제한하고 잠재적인 문제를 피하는 것이 더 나았습니다.

당신이 사용하는 경우 NVARCHAR 시스템 저장 프로시저에 필요하기 때문에 가장 자주 발생하는 것은 설명할 수 없는 일입니다. sp_executesql, 이고 동적 SQL이 매우 길기 때문에 성능 측면에서 모든 문자열 조작(연결, 교체 등)을 수행하는 것이 더 나을 것입니다. VARCHAR 그런 다음 최종 결과를 다음으로 변환합니다. NVARCHAR proc 매개변수에 입력합니다.아니요, 항상 사용하지는 마세요. NVARCHAR!

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top