광범위한 PK와 별도의 합성 키 및 UQ 사용 간의 성능 고려 사항은 무엇입니까?


10

여러 비즈니스 분야에서 레코드를 고유하게 식별 할 수있는 여러 테이블이 있습니다. 과거에는 다음과 같은 이점을 염두에두고이 필드를 PK로 사용했습니다.

  • 간단; 외부 필드가없고 하나의 인덱스 만 있습니다
  • 클러스터링은 빠른 병합 조인 및 범위 기반 필터를 허용합니다

그러나 합성 IDENTITY INTPK 를 만들고 별도의 UNIQUE제약 조건으로 비즈니스 키를 시행 하는 사례를 들었습니다 . 좁은 PK는 훨씬 작은 2 차 지수를 만든다는 장점이 있습니다.

테이블 에 PK 이외의 인덱스 없으면 두 번째 방법을 선호하는 이유는 없지만 큰 테이블에서는 나중에 인덱스가 필요할 수 있다고 가정하는 것이 가장 좋으며 따라서 좁은 합성 PK를 선호하는 것이 가장 좋습니다 . 고려 사항이 누락 되었습니까?

덧붙여서, 저는 데이터웨어 하우스에서 합성 키를 사용하는 것에 대해 논쟁하지 않고 단일 PK를 언제 사용할 것인지, 좁은 PK와 영국을 사용할 때에 만 관심이 있습니다.


1
당신이 찾을 수 또는 사이트에 다른 질문들 도움을
잭 topanswers.xyz 시도라고

답변:


11

고유 키를 클러스터형 인덱스로 사용하면 큰 단점이 없습니다.

  • 비 클러스터형 인덱스가 없습니다
  • 이 테이블을 참조하는 외래 키가 없습니다 (부모 행임)

데이터 인서트가 끝이 아닌 데이터 전체에 분산되므로 페이지 분할이 늘어납니다.

FK 또는 NC 인덱스가있는 경우 폭이 좁고 숫자가 클수록 클러스터형 인덱스를 사용하면 유리합니다. while 비즈니스 / 자연 키가 아닌 NC 또는 FK 항목 당 몇 바이트의 데이터 만 반복합니다.

이유에 대해서는 Google에서 너무 많은 기사를 읽습니다.

참고 "기본 키"사용을 피했습니다.

서로 게이트 키에 클러스터 된 인덱스를 가질 수 있지만 PK를 비즈니스 규칙에 유지하지만 클러스터되지 않은 상태로 유지할 수 있습니다. SQL이 클러스터를 만들기 위해 "고유 자"를 추가하기 때문에 클러스터가 고유한지 확인하십시오.

마지막으로 대리 키가 있지만 모든 테이블에 맹목적으로있는 것은 아닙니다 . 많은 테이블이 필요하지 않거나 상위 테이블의 복합 키로 충분합니다.


색인에서 참조 Tripp 부인 기사에 +1.
Fabricio Araujo

2
성능은 기본 키 및 인덱스와 관련된 모든 것과 관련이 없다는 점에서 +1입니다.
nvogel

4

명백한 내용을 언급 할 위험이 있지만, 대리 키 (ID 번호)의 색인은 ID 번호로 물건을 찾아야하는 경우 유용합니다. 사용자는 ID 번호를 다루지 않을 것입니다. 그들은 사람이 읽을 수있는 텍스트를 다룰 것입니다. 따라서 텍스트와 해당 ID 번호를 많이 전달해야하므로 사용자 인터페이스가 텍스트를 표시하고 ID 번호에서 작동 할 수 있습니다.

dbms는 이러한 종류의 인덱스를 사용하여 외래 키를 지원하는 경우 외래 키를 지원합니다.

ID 번호를 외래 키로 사용하여 성능을 향상시킬 수는 있지만 절대적으로 개선되는 것은 아닙니다. 우리의 OLTP 시스템에서, 자연 키를 사용하는 외래 키는 약 130 (제 생각) 대표 쿼리의 테스트 스위트에서 ID 번호를 사용하는 외래 키보다 성능이 뛰어납니다. (중요한 키를 사용하면 중요한 정보가 키에 자주 전달되므로 많은 조인을 피할 수 있습니다 .) 중간 속도 증가는 85의 요인이었습니다 (ID 번호를 사용하는 행은 행을 반환하는 데 85 배 더 오래 걸렸습니다).

테스트에 따르면 특정 테이블이 수백만 행에 도달 할 때까지 데이터베이스의 자연 키 읽은 것보다 id 번호에 대한 조인이 더 빨리 수행되지 않습니다 . 행의 너비는 그와 관련이 있습니다. 행이 넓을수록 페이지에 맞는 행 수가 적으므로 'n'개의 행을 얻으려면 더 많은 페이지를 읽어야합니다. 거의 모든 테이블이 5NF에 있습니다. 대부분의 테이블은 상당히 좁습니다.

조인이 여기 에서 간단한 읽기를 수행하기 시작할 때 중요한 테이블과 인덱스를 솔리드 스테이트 디스크에두면 성능이 수억 행에 도달 할 수 있습니다.


3

클러스터링 + pk에 대한 ID 열을 사용하여 설계된 전체 oltp 데이터베이스가 있습니다. 그것은 / 삽입에 꽤 빨리 일을 추구하지만 난 몇 가지 문제를 본 적이 :
인서트가 인덱스의 끝 부분에만 발생하기 때문에 1. 인덱스 채우기 옵션이 쓸모
2. 더 많은 저장 공간. 나는 수천만 개의 레코드를 가진 테이블을 가지고 있으며 1 int는 그 자체로 공간을 차지합니다. pk에 대한 ID 열이있는 각 테이블에는 비즈니스 검색을위한 다른 인덱스가 있어야하므로 더 많은 스토리지가 필요합니다.
3. 확장 성. 이것이 최악의 문제입니다. 모든 삽입은 색인의 끝으로 이동하기 때문에 각 삽입은 색인의 끝 (할당, 쓰기의 io 등) 만 강조합니다. 비즈니스 키를 클러스터링 키로 사용하면 인덱스에 삽입물을 균등하게 분배 할 수 있습니다. 즉, 큰 핫스팟을 제거했을뿐입니다. 인덱스에 더 많은 파일을 사용할 수 있으며, 각 파일은 별도의 드라이브에 있으며, 각 드라이브는 별도로 작동합니다.

테이블을 자격 증명 열에서 자연 키로 변경하기 시작했습니다 (클러스터링 및 pk와는 별도로있을 수 있음). 기분이 나아졌습니다.

다음을 제안합니다 (적어도 oltp db의 경우).
1. 가장 빈번한 쿼리를 최적화하기 위해 올바른 순서로 올바른 열을 클러스터링 키로
사용하십시오.

클러스터 된 키가 단순하지 않고 문자 (char [], varchar, nvarchar)가 포함되어 있다면 대답이 '의존적'이라고 생각하면 각 경우를 개별적으로 분석해야합니다.

최악의 시나리오를 최소화하면서 가장 일반적인 쿼리를 최적화하는 다음 원칙을 유지합니다.

나는 하나의 예를 거의 잊었다. 자체를 참조하는 테이블이 있습니다. 해당 테이블에 기본 키에 대한 ID 열이있는 경우 하나의 행을 삽입하려면 업데이트가 필요할 수 있으며 한 번에 둘 이상의 행을 삽입하는 것은 불가능하지는 않지만 어려울 수 있습니다 (테이블 디자인에 따라 다름).


4
"핫스팟"개념은 신화입니다 : dba.stackexchange.com/questions/1584/… 그리고 "지금 기분이 나아졌습니다." 벤치마킹 했습니까?
gbn

4
그러나 쓰기는 디스크에 직접 저장되지 않고 메모리에서 수행됩니다. 페이지에 20 개의 새 행을 쓰면 검사 점이 발생할 때 데이터 파일에 물리적으로 한 번만 기록됩니다.
mrdenny

인덱스의 끝에 모든 것을 쓰는 충분한 삽입을 가진 @mrdenny는 모든 io 쓰기 요청을 동일한 파일로 보냅니다. 정상적인 oltp 트랜잭션을 사용하면이 시나리오를 재현하기 어려울 것으로 예상되지만 대량 / 배치 삽입 레코드와 같은 특수 시나리오를 사용하여 ssis를 사용하여 일부 비즈니스 데이터를 이동하면 얻을 수 있습니다.
Catalin Adler

1
@ user973156 예, 모든 요청은 동일한 파일에 대해 수행되지만, 1 분마다 (기본적으로) 만 발생하거나 쓰기 버퍼가 50 % 가득 찰 때까지 실제로 검사는 디스크로 이동하지 않습니다. 이 규칙이 여전히 적용되는 데이터를 작성하는 방법은 중요하지 않습니다.
mrdenny

2
@ user973156 무작위로 분산 된 클러스터링 키를 사용하면 인덱스 조각화가 발생합니다. 인덱스 조각화로 인해 성능 문제가 발생합니다. 또한 인덱스 조각 모음을 수행하는 데 "시간이 오래 걸리고 로그 공간과 잠재적으로 tempDB 공간을 차지할 정도로 테이블이 충분히 커집니다. Kimberly Tripp와 같은 사람들에게 좋은 생각이라고 들었을 때 들었습니다. ( sqlskills.com/BLOGS/KIMBERLY/post/… )
Matt M

2

성능 관점에서 어떤 키가 "기본"키인지 선택하면 아무런 차이가 없습니다. PRIMARY KEY와 UNIQUE 제약 조건을 사용하여 키를 적용하는 것에는 차이가 없습니다.

성능은 인덱스 선택 및 유형 및 기타 스토리지 옵션과 쿼리 및 코드에서 키가 사용되는 방식에 따라 결정됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.