NVARCHAR 열을 PRIMARY KEY 또는 UNIQUE 열로


11

SQL Server 2012 데이터베이스를 개발 중이며 기본 키로 nvarchar 열에 대한 의문이 있습니다.

나는이 테이블을 가지고있다 :

CREATE TABLE [dbo].[CODES]
(
    [ID_CODE] [bigint] IDENTITY(1,1) NOT NULL,
    [CODE_LEVEL] [tinyint] NOT NULL,
    [CODE] [nvarchar](20) NOT NULL,
    [FLAG] [tinyint] NOT NULL,
    [IS_TRANSMITTED] [bit] NOT NULL DEFAULT 0,
     CONSTRAINT [PK_CODES] PRIMARY KEY CLUSTERED 
    (
        [CODE_LEVEL] ASC,
        [CODE] ASC
    )
)

그러나 이제 [CODE]열을 기본 키로 사용하고 열을 제거 하고 싶습니다 [ID_CODE].

NVARCHAR열 이 있으면 문제 또는 페널티가 PRIMARY KEY있습니까?

[CODE]열 값은 고유해야하므로 UNIQUE해당 열에 제약 조건을 설정할 수 있다고 생각했습니다 .

[CODE]기본 키로 사용해야 합니까, 아니면 열에 UNIQUE제약 조건을 설정하는 것이 좋습니다 [CODE]?


1
고려해야 할 중요한 것은 테이블에 몇 개의 행이 있는지입니다.
제임스 Z

이것은 그 자체 로 답은 아니지만 CODE열이 고유해야하지만 기본 키는 아니라고 생각합니다 . 나는 그것이 정보를 가지고 있다고 생각합니다. 해당 정보가 어떤 방식 으로든 변경 가능한 경우, 귀하 CODE는 변경되거나 최신 정보가 아니어야합니다. 그러면 기본 키가 휘발성이되어 종료가 잘 보이지 않습니다. PK를 열쇠로 삼는 것이 가장 좋으며 CODE는 원하는 것을 할 수 있습니다. 그냥 의견.
Manngo

@Manngo, 귀하의 의견에 감사드립니다. 그렇습니다. ID_CODE는 기본 키이고 CODE는 고유합니다.
VansFannel

답변:


13

그렇습니다. 기본 키에 숫자 유형 대신 문자열을 사용하면 부정적인 결과가 발생하며 PK가 클러스터 된 경우 (실제로 귀하의 경우) 더욱 그렇습니다. 그러나 문자열 필드를 사용하는 효과는 a)이 테이블에있는 행 수 및 b)이 테이블에 외래 키가 지정된 다른 테이블의 행 수의 함수입니다. 이 테이블에 10k 개의 행만 있고 해당 필드를 통해이 테이블에 FK되는 다른 몇 개의 테이블에 100k 개의 행만있는 경우 그렇게 눈에 띄지 않을 수 있습니다. 그러나 행 개수가 증가함에 따라 이러한 효과가 더욱 두드러집니다.

클러스터형 인덱스의 필드가 비 클러스터형 인덱스로 이월되는 것을 고려해야합니다. 따라서 행 당 최대 40 바이트를 보는 것이 아니라 (40 * some_number) 바이트입니다. 그리고 모든 FK 테이블에서 행에 동일한 40 바이트가 있고 JOIN에서 사용되는 것처럼 해당 필드에 비 클러스터형 인덱스가있는 것보다 자주 발생하므로 이제 FK 테이블에서 두 배가됩니다. 이 하나. 40 바이트 * 1 백만 행 * 10 복사본에 대해 걱정할 필요가 없다면 내 기사 Disk is Cheap! 를 참조하십시오 . 오랄? 이 결정에 영향을받는 모든 영역 (또는 최소한)을 자세히 설명합니다.

고려해야 할 또 다른 사항은 문자열 필터링 및 정렬, 특히 이진 데이터 정렬을 사용하지 않는 경우 (대개 대소 문자를 구분하지 않는 데이터베이스 기본값을 사용한다고 가정)는 INT/를 사용할 때보 다 훨씬 덜 효율적입니다 (즉, 시간이 더 오래 걸림) BIGINT. 이는이 필드에서 필터링 / 결합 / 정렬하는 모든 쿼리에 영향을줍니다.

따라서 CHAR(5)Clustered PK에는 이와 비슷한 것을 사용하는 것이 좋을 수도 있지만 대부분이 PK로 정의 된 경우 COLLATE Latin1_General_100_BIN2(또는 이와 유사한 것) 가능합니다.

그리고 [CODE]이제까지 의 가치 가 변할 수 있습니까? 그렇다면 PK로 사용하지 않는 것이 더 많은 이유입니다 (FK를로 설정하더라도 ON UPDATE CASCADE). 변경할 수 없거나 변경되지 않는 경우에도 클러스터 PK로 사용하지 않는 충분한 이유가 있습니다.

물론 현재 PK에이 필드가 이미있는 것 같으므로 질문이 잘못 표현되었을 수 있습니다.

에 관계없이, 당신의 최선의 선택은, 지금까지 사용하는 것입니다 [ID_CODE]FK 같은 관련 테이블의 필드, 그리고 유지하는 것이, 클러스터 된 PK로 사용을 [CODE]A와 UNIQUE INDEX(그것이 "대체 키"입니다 의미).



이 답변에 대한 의견 에서이 질문에 대한 좀 더 많은 정보를 업데이트하십시오 :

[CODE] 열을 사용하여 테이블을 조회하는 경우 [ID_CODE]가 PRIMARY KEY로서 가장 좋은 옵션입니까?

이 모든 것은 매우 많은 요소에 달려 있으며, 그중 일부는 이미 언급했지만 다시 언급 할 것입니다.

기본 키는 외래 키에 의해 참조되는지 여부에 관계없이 개별 행을 식별하는 방법입니다. 시스템이 행을 내부적으로 식별하는 방법은 사용자가 자신을 식별하는 방법과 반드시 ​​동일하지는 않습니다. 고유 한 데이터 가있는 NOT NULL 열 작동 할 수 있지만 특히 PK가 실제로 FK에 의해 참조되는 경우 고려해야 할 실질적인 문제가 있습니다. 예를 들어 GUID는 독특하고 일부 사람들은 여러 가지 이유로 GUID를 사용하는 것을 정말로 좋아하지만 클러스터형 인덱스에는 좋지 NEWSEQUENTIALID않습니다 ( 더 좋지만 완벽하지는 않습니다). 반면 GUID는 대체 키처럼 훌륭하고 행을 조회하는 데 앱에서 사용되지만 JOIN은 여전히 ​​INT (또는 유사한) PK를 사용하여 수행됩니다.

지금까지는 [CODE]필드가 모든 각도에서 시스템에 어떻게 적용되는지 알려주지 않았습니다. 지금은 이것이 행을 찾는 방법이지만 모든 쿼리 또는 일부에 대한 것입니까? 그 후:

  • [CODE]값 과 관련하여 :

    • 어떻게 생성됩니까?
    • 증분 또는 의사 랜덤입니까?
    • 길이가 균일합니까 아니면 길이가 변합니까?
    • 어떤 문자가 사용됩니까?
    • 알파벳 문자를 사용하는 경우 : 대소 문자를 구분합니까?
    • 삽입 한 후에도 바꿀 수 있습니까?
  • 이 테이블과 관련하여 :

    • 이 테이블에 다른 테이블이 있습니까? 또는 명시 적으로 외래 키가 아니더라도 이러한 필드 ( [CODE]또는 [ID_CODE])가 다른 테이블에서 사용됩니까?
    • 경우 [CODE] 유일한 필드는 개별 행을 가져 오는 데 사용됩니다, 다음, 어떤 목적 않는 [ID_CODE]필드 봉사? 그것이 사용되지 않는다면, 왜 처음에 그것을 가지고 [CODE]있습니까?
    • 이 테이블에 몇 개의 행이 있습니까?
    • 다른 테이블이이 테이블을 참조 할 경우 각 테이블에 몇 개의 행이 있습니까?
    • 이 테이블의 인덱스는 무엇입니까?

이 결정은 순전히 "NVARCHAR 예 또는 아니오?"에 관한 질문으로 이루어질 수 없습니다. 다시 말하지만 일반적으로 말하면 그것이 좋은 생각이라고 생각하지는 않지만 확실히 괜찮을 때가 있습니다. 이 테이블에 필드가 너무 적 으면 더 이상 또는 적어도 많은 인덱스가 없을 것입니다. 따라서 [CODE]클러스터형 인덱스로 사용하는 것이 좋습니다. 그리고 다른 테이블이이 테이블을 참조하지 않으면 PK로 만들 수도 있습니다. 그러나 다른 테이블이이 테이블을 참조하는 [ID_CODE]경우 비 클러스터형이라도 필드를 PK로 선택합니다 .


익명의 downvoter (누군가 @noIDonthissystem의 답변을 다운 투표 한 것으로 보임)가 건설적인 비판을 제공하거나 결함이있는 논리를 지적하도록주의를 기울입니까?
Solomon Rutzky

답변 주셔서 감사합니다. 가 [ID_CODE]아니라, PRIMARY KEY내가 사용하는 경우 최선의 선택, [CODE]열이 테이블을 찾아 볼 수는?
VansFannel

@VansFannel 내 업데이트를 참조하십시오. 감사.
Solomon Rutzky

이 답변을 찬성하기 위해이 dba 커뮤니티에 가입했습니다.
Ahmet Arslan

6

개념을 분리해야합니다.

  • 기본 키설계 개념으로, 테이블 항목의 논리적 속성입니다. 테이블 항목의 수명 동안 변경 불가능하며 항목을 참조하기 위해 응용 프로그램에서 사용되는 키 여야합니다.

  • 클러스터형 인덱스스토리지 개념, 물리적 속성입니다. 쿼리에 대한 가장 일반적인 액세스 경로 여야하며, 대부분의 경우 인덱스를 포함하는 것으로 만족하고 가능한 한 많은 범위 쿼리를 만족시켜야합니다.

기본 키가 클러스터형 인덱스 일 필요는 없습니다. ID_CODEPK 및 (CODE_LEVEL, CODE)클러스터 키로 사용할 수 있습니다 . 아니면 다른 방법.

키가 클수록 인덱스 페이지의 밀도가 낮아지고 모든 비 클러스터형 인덱스에서 소비되는 크기가 커짐에 따라 더 큰 클러스터 키에는 부정적인 영향이 있습니다. 예를 들어 이미이 주제에 잉크가 쏟아져 나왔습니다. 클러스터링 키에 대한 추가 고려 사항 부터 시작 – 클러스터형 인덱스 토론이 계속됩니다! .

그러나 문제의 핵심은 클러스터형 인덱스 키의 선택이 주로 트레이드 오프라는 것입니다. 한편 성능에 일반적으로 영향 스토리지 크기 요구 사항이 (-> 더 큰 크기 - 큰 키> 더 IO 및 IO 대역폭은 아마도 당신이 가장 부족한 자원). 반면 공간 절약이라는 이름으로 잘못된 클러스터 키를 선택하면 쿼리 성능에 영향을 줄 수 있으며 넓은 키로 인해 발생하는 문제보다 더 나빠질 수 있습니다.

기본 키 선택에 관해서는 문제가되어서는 안됩니다. 데이터 모델, 앱 논리는 기본 키가 무엇인지를 지시해야합니다.

즉, 내 2c NVARCHAR(20)는 넓지 않습니다 . 큰 테이블에서도 완벽하게 허용되는 클러스터 키 크기입니다.


답변 주셔서 감사합니다. 가요 [ID_CODE], 등 PRIMARY KEY, 최선의 선택 내가 사용하는 경우 [CODE](어쩌면 및 열 [CODE_LEVEL]) 테이블을 찾으려면?
VansFannel

@VansFannel 만 대답 수 있습니다.
레무스 루사 누

그러나 당신의 의견에 ...
VansFannel

2
내 의견으로는 전체 테이블과 모든 인덱스의 정확한 DDL, 테이블을 참조하는 외래 키, 예상 행 수, 예상 쿼리 워크로드, 응용 프로그램 예상 SLA 및 하드웨어 및 라이센싱에 사용 가능한 최소한의 SDL을 고려해야합니다.
레무스 루사 누

감사. [CODE]PRIMARY KEY로 열을 사용 합니다.
VansFannel

4

누구도 nvarchar(20)데이터베이스에서 PK가 될 수 없습니다. 디스크 공간과 캐시 메모리를 낭비합니다. 이 테이블의 모든 인덱스와 이에 대한 모든 FK는이 넓은 값을 복제합니다. 그들이 정당화 할 수 있다면 아마 char (20). 어떤 종류의 데이터를 저장하려고 CODE합니까? nvarchar 문자를 저장해야합니까? PK를 사용자가 볼 수없는 "내부"값으로 만드는 경향이 있으며 표시되는 값을 별도로 유지하려고합니다. 표시되는 값은 때때로 변경되어야하는데, 이는 PK + FK에서 매우 문제가됩니다.

또한 'bigint identity (1,1)'이 최대 9,223,372,036,854,775,807까지 증가 할 수 있다는 것을 알고 있습니까?

[ID_CODE] [bigint] IDENTITY(1,1)

이 데이터베이스를 Google 용으로 구축하지 않는 한 int identity (1,1)20 억을 초과 하는 표준 으로는 충분하지 않습니까?


int는 SQL에서 4 바이트이며 -2.1Billion ~ + 2.1Billion을 제공합니다.
datagod

@ datagod, 하 고마워요, 너무 많은 숫자를 잘못 계산했습니다!
이 시스템에 ID가 없습니다.

답변 주셔서 감사합니다. 가 [ID_CODE]아니라, PRIMARY KEY내가 사용하는 경우 최선의 선택, [CODE]열이 테이블을 찾아 볼 수는? 감사.
VansFannel

누군가가 "int"의 순차적 특성을 사용하여 DB의 데이터 / 사용자를 예측하고 내가 가진 모든 것을 수확 할 때까지이 보트에있었습니다. 다시는 공개 DB는 정보를 얻기가 좀 더 어려워 야합니다.
DaBlue

3

알 수없는 경우 nvarchar / varchar를 사용할 때 와이드 키를 사용할 위험이있는 것 외에는 고유하고 눈에 띄는 페널티가 없어야합니다. 특히 복합 키로 결합을 시작하는 경우.

그러나 (20) 길이의 예에서 당신은 괜찮을 것이고 나는 그것에 대해 많이 걱정하지 않을 것입니다. CODE가 주로 데이터를 쿼리하는 방법 인 경우 그에 대한 클러스터형 인덱스는 매우 합리적입니다.

그러나 실제로 기본 키로 사용할 것인지 아니면 고유 한 (클러스터 된) 인덱스로 원하는지를 고려해야합니다. 클러스터형 인덱스와 기본 키 간에는 작은 차이가 있습니다 (기본적으로 기본 키는 데이터를 식별하지만 인덱스는 데이터를 쿼리하는 방법입니다). 원하는 경우 ID_Code를 기본 키로 쉽게 만들 수 있습니다. CODE를 통해 고유 한 클러스터형 인덱스를 만듭니다. 참고 : 클러스터형 인덱스를 직접 만들지 않은 경우 SQL Server에서 기본 키를 자동으로 클러스터형 인덱스로 만듭니다.

또한 실제로 ID_Code가 필요한지 고려하십시오. 이제 고유 한 CODE가 있습니다.


2
사실 NVARCHAR(20)이다 (40) 의 크기 (최대) 바이트, 그리고 그것의 이후 가변 길이 열, 정말 클러스터 된 인덱스를위한 최선의 선택이 아니다. ID_CODE있는 것은 BIGINT IDENTITY것이 훨씬 더 여기에 선택!
marc_s

나는 그것이 40 바이트라는 것을 알고 있지만 900 바이트 근처에있는 것으로 보지 않고 그것을 지정할 이유가 많지 않았습니다. 당신이 주로 코드에서 데이터를 조회하는 경우는 여전히에 인덱스를 필요 했어, 다음은 클러스터 aftwards를 통해 조회해야 할 것 때문에 그것은 중복 인덱스를 유지하는 것을 피하기 위해 더 나은 선택이 될 것입니다
앨런 S. 한센

언급 할 가치가 없으며 @marc_s가 해결하는 곳은 의심의 여지가 있습니다.이 유형의 색인은 순차적 ID보다 색인 조각화가 더 커질 수 있지만 여전히이 특정 상황에서 합리적인 색인으로 간주합니다 질의 요인에.
Allan S. Hansen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.