PK 목적으로 만 자동 증분 / IDENTITY 필드를 상호 참조 테이블에 추가해야합니까?


9

SQL Server 호스팅 DB에 다음 상호 참조 테이블을 추가하고 있습니다.

company_id bigint not null (FK)
org_path nvarchar (2048) not null

company_id필드는 id다른 테이블 (기본 키) 의 필드를 나타냅니다 .

가 같은 레코드가 여러 개있을 수 있으므로 company_id기본 키는 두 필드를 모두 사용해야합니다. 그러나 org_pathSQL Server에 비해 너무 길기 때문에 두 필드를 모두 사용하여 키를 만들 수 없습니다 .

에 관해서는 org_path이것이 존재하는 유일한 테이블입니다. 이 테이블에 대한 쿼리가에 의해 모든 항목 또는 모든 org_path항목을 요구할 가능성이 있습니다 company_id. 또는 다른 식으로 말하면이 테이블이에 의해 쿼리 될 것 같지 org_path않습니다. 또한 org_path업데이트 될 가능성이 적으며 삽입 및 삭제 가능성이 적습니다 .

총 행 수는 수천 개가 될 것으로 예상합니다.

또한 그 이유 nvarchar (2048)는 가치가 타사 DB의 값을 모방해야하기 때문입니다. 전형적인 예는 다음과 같습니다

\Translation Providers\[customer name]\[order name]\

분음 부호를 포함 할 수 있습니다.

그래서 내 질문은 이것입니다 : 자동 증가 id필드 를 추가 company_id하고 기본 키 와 함께 사용 하거나 불필요한 오버 헤드 를 추가하는 것이 더 효율적 입니까- company_id다른 테이블의 기본 키라는 사실 이 있습니까? 여기에 효과?

답변:


7

고유하지 않은 클러스터형 인덱스의 comany_id경우 SQL Server는 모든 복제 된 (즉, 키 값에 대한 두 번째 및 그 이후의) 클러스터형 인덱스 키에 4 바이트 정수 고유자를 자동으로 추가하여 고유하게 만듭니다. 그러나 이것은 사용자에게 노출되지 않습니다.

고유 한 식별자를 보조 키 열로 추가하면 장점을 통해 검색 할 수 company_id있지만 개별 행을보다 효율적으로 검색 할 수 있다는 장점이 있습니다 ( 잔류 조건 자를 on company_id, identitycol대신 사용 ). 그러면 클러스터형 인덱스가에 고유 하므로 숨겨진 고유 식별자가 추가되지 않습니다.company_idorg_pathcompany_id, identitycol

또한에 대한 중복 (company_id,org_path)이 발생하는 경우 명시 적 ID 열 ( "노출 된 고유 식별자")을 사용하면 삭제 또는 업데이트를 위해 이들 중 하나만 쉽게 타겟팅 할 수 있습니다.


12

고려해야 할 한 가지는 기본 키와 클러스터형 인덱스가 같지 않다는 것입니다. 기본 키는 제약 조건이며 데이터가 존재하는 규칙 (예 : 데이터 무결성)을 처리합니다. 효율성 / 성능과 관련이 없습니다. 기본 키를 사용하려면 키 열이 고유하고 (조합하여) NOT NULL (개별적으로)이어야합니다. PK는 고유 인덱스를 통해 적용되지만 클러스터 또는 비 클러스터 일 수 있습니다.

클러스터형 인덱스는 테이블의 데이터를 물리적으로 (즉, 디스크에) 정렬하는 수단이며 성능을 처리합니다. 데이터 무결성과는 아무런 관련이 없습니다. 클러스터형 인덱스 키 열은 고유해야하며 (조합으로) 필요하지는 않습니다. 그러나 Clustered Index는 데이터의 물리적 순서이므로 각 행을 고유하게 식별해야합니다. 따라서 고유성을 요구하지 않도록 설정하면 숨겨진 4 바이트 "고유 자"열을 통해 고유 한 고유성을 생성합니다. 해당 열은 항상 고유하지 않은 클러스터형 인덱스에 있지만 키 필드가 고유 할 때 공간을 차지하지 않습니다 (조합). 이 "고유 화기"열의 작동 방식 (클러스터형 인덱스 및 비 클러스터형 인덱스에 미치는 영향)을 직접 확인하려면 PasteBin : T-SQL 스크립트 에 게시 한이 테스트 스크립트를 확인하십시오 .

따라서 다음의 주요 질문은

자동 증가 id필드 를 추가하고 company_id이를 기본 키 와 함께 사용하는 것이 더 효율적 이거나 불필요한 오버 헤드를 추가 하는가

이 두 개념을 혼동하고 있기 때문에 약간의 중복이 있지만 개별적으로 해결해야합니다.

IDENTITY열을 추가 해야합니까 아니면 불필요한 오버 헤드가 필요합니까?

INT IDENTITY컬럼 을 추가하고 이를 사용하여 PK를 작성하는 경우 클러스터 된 PK라고 가정하면 모든 행에 4 바이트가 추가됩니다. 이 열은 쿼리에서 볼 수 있고 사용할 수 있습니다. 그것은 할 수 있지만 발생하지 않습니다이 특정한 경우에, 외래 키로 다른 테이블에 추가 될 수있다.

INT IDENTITY열을 추가하지 않으면 이 테이블에서 PK를 만들 수 없습니다. 그러나 UNIQUE옵션을 사용하지 않는 한 테이블에 클러스터형 인덱스를 만들 수 있습니다 . 이 경우 SQL Server는 "uniquifier"라는 숨겨진 열을 추가하여 위에서 설명한대로 작동합니다. 열이 숨겨져 있으므로 쿼리 나 외래 키에 대한 참조로 사용할 수 없습니다.

효율성이 향상되는 한 이러한 옵션은 거의 동일합니다. 예, 일부 행 (초기 고유 키 값이있는 행)이 0 바이트를 차지하고 / PK의 모든 행 이 4 바이트를 차지하기 때문에 고유하지 않은 클러스터형 인덱스로 인해 차지하는 공간 이 약간 줄어 듭니다 IDENTITY. 그러나 ID쿼리 에서 열 을 사용할 수있는 편리함을 능가하지는 않지만 0 바이트 행 (특히 소량의 행이 예상 됨)이 차이를 알기에 충분하지 않습니다 .

INT IDENTITY 열 또는 org_path지속 된 계산 열의 해시 ?

org_path값을 기반으로 행을 찾지 않을 경우 Persisted Computed Column의 오버 헤드를 추가하고 Computed Column과 일치시키기 위해 쿼리에서 해시를 계산 해야하는 것이 합리적이지 않습니다. 여기 에서 개정 이력에서 사용할 수있는 최초 제안 ( 질문의 초기 문구 / 세부 사항을 기반으로 함). 이 경우 INT IDENTITY"ID"열이 가장 적합합니다.

키 열 순서

점을 감안 ID열이 거의 어느 경우 쿼리에서 사용하지됩니다 두 가지 주요 사용 사례 중 하나 "모든 행"또는 "주어진 모든 행을 얻을 수 있음을 주어 company_id"나는에 PK를 만들 것입니다 company_id, id. 이는 행이 순차적으로 삽입되지 않음을 의미하므로 FILLFACTOR90을 지정합니다 . 조각화를 줄이려면 정기적 인 인덱스 유지 관리를 수행해야합니다.

두번째 질문

company_id가 다른 테이블의 기본 키라는 사실이 여기에 영향을 미칩니다.

아니.

방아쇠

org_path내의 값 company_id은 고유 하기 때문에 INSERT, UPDATE이를 적용하려면 트리거를 작성해야 합니다. 트리거에서 IF EXISTSa COUNT(*)및 을 수행하는 쿼리를 사용하여을 수행하십시오 GROUP BY company_id, org_path. 아무것도 발견되면 a ROLLBACK를 발행 하여 DML 작업을 취소 한 다음 RAISERROR중복이 있음을 알리십시오.

대조

내 초기 답변 (질문의 원래 문구 / 스파 스 세부 정보를 기반으로하고 여기 에서 개정 내역 에서 사용 가능)에서 이진 (즉 _BIN2) 데이터 정렬을 사용하는 것이 좋습니다 . 이제 우리는 정확히 무엇에 대한 통찰력 가지고 org_path입니다, 나는 것 없는 이진 데이터 정렬을 사용하는 것이 좋습니다. 분음 기호가있을 것입니다 때문에, 당신은 언어 적 동등성의 사용을 만들고 싶어.



0

왜 PK가 필요합니까?

비 클러스터형 인덱스로 company_id를 사용하는 것이 어떻습니까?

가장 많이 검색 한 항목은 모든 항목 또는 company_id에 의해 거의 없다고했습니다.
드물게 업데이트 org_path를
삭제
하십시오. 이것이 존재하는 유일한 테이블입니다

Martin Smith의 대답은 필요한
것을 얻을 수 있습니다 .4 바이트 정수 고유자를 자동으로 추가하십시오.
어쩌면 뭔가 빠졌지 만 다른 열이 색인화되어 있지 않으면이 사용 사례에서 목적이 없습니다.

DRI가 우려되는 경우 테이블은 company_id의 FK로 Company 테이블을 사용해야합니다.


야. " 클러스터되지 않은 인덱스로 company_id를 사용하지 않는 이유는 무엇입니까? ": 2 개의 단점이 있기 때문에 1) 공간을 차지하는 것이 1 개 더 많지만 클러스터형 인덱스 테이블이므로 추가 항목이 없습니다. 2) NVARCHAR 필드를 가져 오기 위해 RID 조회가 필요 INCLUDE하지만 열이 아닌 한 테이블을 복제하기 때문에 더 나쁩니다. 사실 PK는 필요하지 않습니다. 중요한 부분은 Clustered Index입니다. 그러나 일단 ID가 있으면 PK와 함께 갈 수도 있습니다. 그리고 내 답변에서 Uniquifier 😃에 대한 연습을위한 새 링크를 참조하십시오.
Solomon Rutzky

@ srutzky 그러나 그것은 4 바이트 정수 고유자를 피하므로 워시로 보았습니다
paparazzo

행이 10k 미만이면 문제가되지 않습니다. 단 4 바이트의 효과를 확인하기 전에 수백만 행에 있어야합니다. 따라서 "모든 행 가져 오기"쿼리의 경우 이러한 옵션에 차이가 없습니다. 그러나 "get for company_id = @param"쿼리의 경우, 특히 모든 행에 대해 RID 조회를 수행 할 필요가없는 경우 company_id가 실제로 주문한 데이터를 갖는 것이 도움이됩니다.
Solomon Rutzky 2016 년

@srutzky Wash는 10K 또는 1G의 세척입니다. OP가 고려해야 할 것은 단지 무언가입니다.
paparazzo 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.