ID 열의 인덱스가 클러스터되지 않아야합니까?


19

식별 컬럼이있는 테이블의 경우 식별 컬럼에 대해 클러스터 또는 비 클러스터 PK / 고유 인덱스를 작성해야합니까?

그 이유는 다른 인덱스가 쿼리에 대해 생성되기 때문입니다. 비 클러스터형 인덱스 (힙에서)를 사용하고 인덱스에 포함되지 않은 열을 반환하는 쿼리는 추가 클러스터 된 인덱스 b- 트리 탐색 단계가 없기 때문에 논리 I / O (LIO)를 덜 사용합니까?

create table T (
  Id int identity(1,1) primary key, -- clustered or non-clustered? (surrogate key, may be used to join another table)
  A .... -- A, B, C have mixed data type of int, date, varchar, float, money, ....
  B ....
  C ....
  ....)

create index ix_A on T (A)
create index ix_..... -- Many indexes can be created for queries

-- Common query is query on A, B, C, ....
select A, B 
from T 
where A between @a and @a+5 -- This query will have less LIO if the PK is non-clustered (seek)

select A, B, C
from T 
where B between @a and @a+5 

....

ID 열의 클러스터 된 PK는 다음과 같은 이유로 좋습니다.

  1. 단조롭게 증가하므로 삽입 할 때 페이지가 분할되지 않습니다. 대량 삽입은 힙 (비 클러스터형) 테이블에서만큼 빠를 수 있다고합니다.

  2. 좁다

그러나 질문의 ​​쿼리를 클러스터로 설정하지 않고 더 빠를까요?

** 업데이트 : ** Id다른 테이블의 FK이고 일부 쿼리에서 조인되는 경우 어떻게됩니까?


3
더 나쁘지 않은가, 그것은 달려 있습니다.
Aaron Bertrand

1
링크 @ypercube kejser.org/clustered-indexes-vs-heaps이 아닌 CI는 LIO 적은을 것이라고 말했다.
u23432534

2
나는 과거에 기사를 읽었으며 클러스터 된 인덱스의 경우와 힙의 경우가 있음을 분명히 지적합니다. 모두 검은 색이나 흰색이 아닙니다.
ypercubeᵀᴹ

4
@ypercube에 대한 귀하의 답변이 최소한 Kejser가 인용 한 기준 중 적어도 하나는 귀하가 공유 한 세부 정보를 만족하는지 확실하지 않습니다. 현재의 형태로, 나는 이것이 거의 모든 단일 시나리오를 포괄해야하기 때문에 유용한 답변을 생성 할 것이라고 확신하지 못합니다. 이는 이미 블로그 게시물에서 인용했습니다. 특정 시나리오에 대한 자세한 내용을 제공 할 수 있으면 게시물의 일부 지식이 적용될 수 있습니다.
swasheck

2
a) 작업량 (OLTP? OLAP? 등?), b) 테이블 크기, c) 일반적인 형식, 몇 가지 예를 들면 다음과 같습니다. 이러한 요소에 대한 세부 정보를 제공하지 않았으므로 권장 사항은 환경의 추측을 기반으로합니다. 또한 제안한 쿼리 (클리어 된 버퍼 포함)를 프로파일 링하고 구성 당 특정 IO 프로파일을 가져 와서 직접 확인하려고하십니까?
swasheck

답변:


16

기본적으로 PK는 클러스터되어 있으며 대부분의 경우 문제가 없습니다. 그러나 어떤 질문을해야합니까?

  • 내 PK를 클러스터해야합니까?
  • 클러스터형 인덱스에 가장 적합한 키는 무엇입니까?

PK와 클러스터형 인덱스는 두 가지 차이점이 있습니다.

  • PK는 제약 사항입니다. PK는 행을 고유하게 식별하는 데 사용되지만 스토리지 개념은 없습니다. 그러나 기본적으로 SSMS에서는 클러스터형 인덱스가없는 경우 고유 한 클러스터형 인덱스에 의해 적용됩니다.
  • 클러스터형 인덱스는 리프 수준에서 행 데이터를 저장하는 특수한 유형의 인덱스로, 항상 포함하고 있습니다. 키의 일부이든 아니든 모든 열은 리프 수준에 저장됩니다. 고유하지 않아도됩니다.이 경우 고유 키 (4 바이트)가 클러스터 된 키에 추가됩니다.

이제 우리는 두 가지 질문으로 끝납니다.

  • 테이블에서 행을 고유하게 식별하려면 (PK)
  • 인덱스의 리프 수준 (Clustered Index)에 저장하려면 어떻게합니까

방법에 따라 다릅니다.

  • 데이터 모델을 설계합니다
  • 데이터를 쿼리하고 쿼리를 작성합니다
  • 데이터를 삽입하거나 업데이트합니다
  • ...

먼저 클러스터형 인덱스가 필요합니까? 대량 삽입하는 경우 정렬되지 않은 데이터를 HEAP (클러스터의 정렬 된 데이터와 비교)에 저장하는 것이 더 효율적입니다. RID (Row Identifier, 8 bytes)를 사용하여 행을 고유하게 식별하고 페이지에 저장합니다.

클러스터형 인덱스는 임의의 값이 아니어야합니다. 리프 수준의 데이터는 색인 키로 저장 및 정렬됩니다. 따라서 조각 화나 페이지 분할을 피하기 위해 계속 증가해야합니다. PK에서이를 수행 할 수없는 경우 다른 키를 클러스터 된 후보로 고려해야합니다. 모든 열이 마지막 리프 페이지에 추가되므로 ID 열, 순차 GUID 또는 삽입 날짜와 같은 항목의 클러스터형 인덱스는 순차 관점에서 적합합니다. 반면, 고유 식별자는 PK로서 비즈니스 요구에 유용 할 수 있지만 클러스터되지 않아야합니다 (임의로 주문 / 생성).

일부 데이터 및 쿼리 분석 후에 클러스터 된 PK에서 키 조회를 수행하기 전에 대부분 동일한 인덱스를 사용하여 데이터를 가져 오는 경우 데이터를 고유하게 식별하지는 않지만 클러스터 된 인덱스로 간주 할 수 있습니다.

클러스터형 인덱스 키는 인덱싱하려는 모든 열로 구성됩니다. 고유 제약 조건이없는 경우 uniquefier 열 (4 바이트)이 추가됩니다 (중복에 대한 증분 값, 그렇지 않으면 null). 이 인덱스 키는 모든 비 클러스터형 인덱스의 리프 수준에서 각 행에 대해 한 번씩 저장됩니다. 그들 중 일부는 인덱스 트리 (B- 트리)의 루트와 리프 레벨 사이의 중간 레벨 (분기)에서 여러 번 저장됩니다. 키가 너무 크면 클러스터되지 않은 모든 인덱스가 커지고 더 많은 스토리지와 더 많은 IO, CPU, 메모리가 필요합니다. name + birthdate + country에 PK가 있으면이 키가 발생할 가능성이 큽니다. 좋은 후보는 아닙니다. 클러스터형 인덱스에 비해 너무 큽니다. NEWSEQUENTIALID ()를 사용하는 고유 식별자는 순차적이지만 좁은 키 (16 바이트)로 간주되지 않습니다.

그런 다음 테이블에서 행을 고유하게 식별하는 방법을 알아 낸 후에 PK를 추가 할 수 있습니다. 쿼리에서 사용하지 않을 것이라고 생각되면 클러스터로 만들지 마십시오. 언젠가 쿼리해야 할 경우 비 클러스터형 인덱스를 계속 만들 수 있습니다. PK는 고유 한 인덱스를 자동으로 생성합니다.

비 클러스터형 인덱스에는 항상 클러스터 된 키가 포함됩니다. 그러나 인덱싱 된 열 (+ 키 열)을 다루는 경우 클러스터형 인덱스에서 키를 찾지 않습니다. 비 클러스터형 인덱스에 Include 및 Where를 추가 할 수도 있습니다. (현명하게 사용하십시오)

클러스터형 인덱스는 고유하고 가능한 한 좁아 야합니다. 클러스터형 인덱스는 시간이 지남에 따라 변경되어서는 안되며 점진적으로 삽입해야합니다.

이제 테이블, 클러스터 및 비 클러스터형 인덱스 및 제약 조건을 생성 할 SQL을 작성할 차례입니다.

사용 된 데이터 모델과 사용 된 데이터 유형 (A 및 B)을 모르기 때문에 이것은 이론적 인 것입니다.


11

ID 열에 기본 키 (PK)가있는 테이블의 경우 기본적으로 클러스터됩니다. 비 클러스터형으로 더 나을 수 있습니까?

기본값을 묻는다면 증명 열의 기본 키 (특히)에 대한 이 클러스터되지 않아야 아니요라고 말합니다. 대부분의 테이블은 클러스터 된 인덱스를 사용하는 이점이 있으므로 기본 키 제약 조건의 클러스터 된 기본값을 만드는 것은 특히 SQL Server의 새로운 사용자에게 도움이 될 것입니다.

거의 모든 옵션과 마찬가지로 하나의 환경이 다른 환경보다 선호되는 환경이 항상 다르지만 경험이 많은 DBA는 기본값을 알고 적절한 경우이를 무시할 수 있어야합니다. 관련 Q & A를 참조하십시오. 기본 키는 언제 비 클러스터형으로 선언해야합니까? .

질문의 쿼리를 클러스터로 설정하지 않고 더 빠릅니까?

예,하지만 경고가 있습니다.

RID 조회는 실제로 키 조회보다 효율적입니다. 필요한 모든 페이지가 메모리에 있더라도 (인덱스의 상위 수준 일 가능성이 높음) 클러스터형 인덱스 b- 트리 탐색과 관련된 CPU 비용이 있습니다. 결과적으로 SQL Server는 일반적으로 CPU 시간 단위당 키 조회보다 더 많은 RID 조회를 수행 할 수 있습니다.

경고

위의 표는 종종 테이블을 힙으로 구성할지 여부를 결정할 때 결정적인 요소가 아닙니다. 조회 (피복 인덱스 사용)를 피하는 것은 비현실적이어야하며, 하드웨어 환경과 워크로드를 고려할 때 조회 수는 성능에 측정 가능하고 중요한 영향을 미칠 정도로 충분히 커야합니다.

이 답변에서 힙 대 클러스터형 인덱스 토론의 모든 측면을 다루는 것은 실제로 실용적이지는 않지만 일반적으로 테이블을 힙으로 구성하는 것을 선호하는 이유는 상대적으로 적습니다. 나에게, 질문에서 제안 된 종류의 디자인을 선택하려면 구현하기 전에 매우 신중한 분석이 필요하며 높은 기준을 충족해야합니다. '확장 성'에 대한 일반적인 주장으로는 충분하지 않습니다.

조인에 대한 질문에 대한 업데이트와 관련하여 클러스터 된 인덱스가 손실되어 실행 계획에 미치는 영향을 평가하면 위에서 언급 한 분석의 일부가됩니다. 중첩 루프 조인을 사용하는 경우 행의 모든 ​​열을 조회하지 않고 즉시 사용할 수 있으므로 조인 키에 클러스터형 인덱스를 갖는 것이 매우 편리합니다.

내 자신의 경험은 ID 열에 고유 한 클러스터형 인덱스를 갖는 것이 종종 유익하다는 것입니다. 모든 것이 고려됩니다. 공간 관리 측면에서 힙에 문제가 있음을 발견했으며 일부 SQL Server 기능이 작동 하려면 고유 한 클러스터형 인덱스가 필요 하다는 점도 언급해야 합니다.


8

고유 인덱스 및 고유하지 않은 인덱스가 작업을 처리 할 수 ​​있으므로 실제로 클러스터형 인덱스 나 기본 키를 만들 필요가 없습니다. SQL Server는 버전 1.1 이상부터 클러스터형 인덱스를 지원했지만 기본 키는 프로그래머가 고유 인덱스를 정의하여 적용한 "개념"입니다.

그러나 기본 키와 클러스터형 인덱스는 대부분의 데이터베이스에서 중요한 개념 인 것 같습니다.

아래에 표시된 것처럼 일부 인덱싱 옵션에 대한 부분 설명을 보려면 SQL Server 설명서를 살펴 보겠습니다.

클러스터형 인덱스 : https://msdn.microsoft.com/en-us/library/ms190457.aspx

  • 클러스터형 인덱스는 키 값을 기준으로 테이블 또는 뷰에서 데이터 행을 정렬하고 저장합니다. 이들은 색인 정의에 포함 된 열입니다.
  • 테이블 당 하나의 클러스터형 인덱스 만있을 수 있습니다

기본 키 : https://msdn.microsoft.com/en-us/library/ms190457.aspx

  • 테이블에는 PRIMARY KEY 제약 조건이 하나만 포함될 수 있습니다.

  • PRIMARY KEY 제약 조건 내에 정의 된 모든 열은 NOT NULL로 정의해야합니다.

  • 기본 키는 클러스터형 인덱스 (클러스터형 인덱스가없는 경우 기본값) 또는 비 클러스터형 인덱스로 만들 수 있습니다.

고유 색인 : https://msdn.microsoft.com/en-us/library/ms187019.aspx

  • UNIQUE 제약 조건을 만들면 기본적으로 UNIQUE 제약 조건을 적용하기 위해 고유 한 비 클러스터형 인덱스가 만들어집니다.

  • 테이블에 대해 클러스터형 인덱스가 존재하지 않는 경우 UNIQUE 클러스터형 인덱스를 지정할 수 있습니다.

즉, 클러스터형 인덱스 및 기본 키에 대한 질문은 실제로 다음 문제 중 일부에 관한 것입니다. 모든 테이블이 동일한 인덱싱 계획의 혜택을받는 것은 아닙니다.

기본 키와 클러스터형 인덱스를 분리하면 언제 혜택을 얻을 수 있습니까?

클러스터형 인덱스가 넓은 경우 (예 : 텍스트 열이 5 개이지만 설명하는 것처럼 기본 키가 작은 경우 (INT 또는 BIGINT)).

  • 넓은 클러스터형 인덱스를 사용하면 클러스터형 인덱스 ( 테이블 이라고도 함) 에서 일련의 답변을 제공하는 쿼리의 하위 집합에 대해 인덱스에서 행을 빠르게 선택할 수 있습니다 . 예를 들어, 5 열 클러스터형 인덱스는 C1, C2, C3, C4, C5 또는 C1, C2, C3, C4 등을 C1까지 스캔하는 것을 지원합니다.
  • 참고 : 행이 큰 경우 특히 테이블의 다른 열이 정기적으로 결과 집합에 포함 된 경우 일련 의 행 집합 을 선택하면 속도가 약간 향상 될 수 있습니다 .
  • 이 경우 참조 무결성을 위해 기본 키 를 사용하여 필요한 값을 외래 키로 제공하여 다른 테이블의 행을 제한 할 수 있습니다. PK는 작으므로 FK는 참조 된 테이블 크기에 작은 영향을 미칩니다.
  • 그러나 클러스터형 인덱스가있는 테이블에서 생성 된 인덱스는이 테이블에서 생성 한 다른 인덱스의 모든 클러스터 열을 포함합니다. 넓은 클러스터형 인덱스는 해당 테이블에있는 모든 비 클러스터형 인덱스의 크기를 확장합니다.

기본 키만 클러스터형 인덱스로 만들어야합니까?

  • 기본 키 (INT 또는 BIGINT)가 작고 클러스터형 인덱스 인 경우 클러스터 열의 오버 헤드는 상대적으로 작습니다. 이 경우 클러스터 된 기본 키가이 테이블의 모든 인덱스에도 존재하지만 위에서 논의한 와이드 클러스터보다 지불 비용이 저렴합니다.

  • 이 기본 키 클러스터형 인덱스는 일반적으로 많은 행을 직렬로 선택할 수있는 쉬운 경로를 직접 제공하지는 않습니다.

  • 클러스터 된 기본 키를 만들었으므로 이전 에 클러스터 된 인덱스에 포함하려는 다른 열은 어떻습니까?

  • C1, C2, C3, C4, C5 열의 광범위한 검색 기준을 색인화하기 위해 필요에 따라 고유 (또는 고유하지 않은) 색인을 작성하십시오. 이“모방 클러스터 된”색인의 값은 해당 5 개의 열에 대한 빠른 검색 경로 역할을 할 수 있습니다. 정기적으로 선택되는 색인화되지 않은 열 또는 두 개가있는 경우을 사용하여 색인에 포함시킬 수 있습니다 INCLUDE (Doctor_Name, Diagnosis_Synopsis).

간단한 클러스터형 인덱스 및 기본 키가 유용하지만 테이블이나 데이터베이스에서 사용할지 여부를 고려해야 할 몇 가지 이유가 있습니다.

클러스터형 인덱스가 필요합니까?

  • 클러스터 된 인덱스의 오버 헤드없이 인덱스 (고유 인덱스 및 비 고유 인덱스)를 만들고 기본 키를 정의하면 인덱스가 좁아 질수록 쿼리에 필요한 것을 제공 할 수 있습니다.

  • 클러스터형 인덱스 및 기본 키에는 유용한 동작이 있지만 실제로 가장 중요한 인덱스라는 점을 기억하십시오. 응용 프로그램의 현실을 고려하여 인덱싱 전략을 설계하십시오. 아마도 OneBigTable대부분의 테이블에 사용하는 것과 다른 인덱싱 전략이 필요할 수 있습니다.

  • 클러스터형 인덱스가 없으면 데이터는 좋은 검색 메커니즘이 아닌 RID (Row Identifier)와 함께 으로 저장됩니다 . 그러나 앞에서 언급했듯이 고유하고 고유하지 않은 인덱스를 만들어 쿼리를 처리 할 수 ​​있습니다.

이제 힙을 고려할 수 있습니다.

힙 및 인덱스 : https://msdn.microsoft.com/en-us/library/hh213609.aspx

  • 테이블이 힙으로 저장되면 개별 행은 파일 번호, 데이터 페이지 번호 및 페이지의 슬롯으로 구성된 행 ID (RID)를 참조하여 식별됩니다. 행 ID는 작고 효율적인 구조입니다. (그러나 색인아닙니다 .)
  • 때때로 데이터 아키텍트 는 비 클러스터형 인덱스를 통해 데이터에 액세스하고 RID가 클러스터형 인덱스 키보다 작은 경우 힙을 사용 합니다 .

그러나 빅 데이터 세트에 '핫스팟'이있는 경우 다른 유형의 인덱스를 조사 할 수도 있습니다.

필터링 된 인덱스 : https://msdn.microsoft.com/en-us/library/cc280372.aspx

  • 잘 설계된 필터링 된 인덱스는 전체 테이블 비 클러스터형 인덱스보다 작고 통계를 필터링하므로 쿼리 성능 및 실행 계획 품질을 향상시킵니다. 필터링 된 통계는 필터링 된 인덱스의 행만 포함하므로 전체 테이블 통계보다 더 정확 합니다.

  • 필터링 된 인덱스에는 필터링 된 인덱스에 대한 링크에 요약 된 여러 제한 사항이 있습니다.

그러나 기본 키와 클러스터형 인덱스를 모두 건너 뛸 수있는 가능성에 대해 관심이있는 경우 아래 링크 된 Markus Winand의 게시물을 읽을 수 있습니다. 그는 일부 코드 샘플을 사용하여 이러한 기능을 사용하는 것을 포기하는 것이 좋은 아이디어라고 제안하는 이유를 설명합니다.

http://use-the-index-luke.com/blog/2014-01/unreasonable-defaults-primary-key-clustering-key

그러나 마지막으로 응용 프로그램을 이해하고 수행중인 작업에 맞게 코드, 테이블, 인덱스 등을 디자인합니다.


가치가있는 것에 대해, 일상적인 작업에서 힙 인 테이블을 찾으면 테이블을 오류로 간주하고 개발자에게 의도적으로 힙이 만들어 졌는지 확인하십시오.
RLF

-2

고려해야 할 몇 가지 사항.

단조롭게 증가하는 값에 대한 인덱스 (클러스터 또는 클러스터되지 않은 인덱스)는 대량 삽입시 페이지 분할을 절약하지만 인덱스의 끝 부분에 새로운 핫스팟을 만듭니다. 단일 스레드 대량 삽입에서는 문제가되지 않지만 스레드가 색인의 마지막 페이지에 액세스하기 위해 지속적으로 경쟁하기 때문에 새로운 튜플을 빠른 속도로 삽입하는 다중 스레드 응용 프로그램에 대한 경합이 확실히 증가합니다.

대리 (ID) PK를 기반으로 테이블을 클러스터링하는 것은 거의 도움이되지 않습니다. 이러한 기본 키는 주로 개별 튜플에 한 번에 하나씩 액세스하거나 전체 색인에서 조인을 스캔하는 데 사용됩니다. 두 경우 모두 인덱스가 클러스터되어 있는지 여부는 중요하지 않습니다 (병합 조인을 제외하고는 얼마나 자주 발생합니까?)

키 범위 스캔을 요구하는 쿼리와 다른 열을 참조하는 추가 술어를 다루는 클러스터형 인덱스의 이점을 최대한 활용할 것이라고 생각합니다.


이것이 실제로 문제가 되려면 속도가 얼마나 높아야합니까?
ypercubeᵀᴹ

@ypercube "의존한다"고 말할 수 있습니까? 그렇기 때문에. 테이블에 트리거가 없으면 초당 총 1K 삽입 수십 개의 스레드로 경합이 발생할 것으로 예상됩니다.
mustaccio


나는 동의하지 않지만 하나의 핫스팟으로 얼마나 멀리 갈 수 있는지 묻고있었습니다. IDENTITY가 CI (메모리가 잘 작동하는 경우)로 테이블에 초당 30K 행을 삽입하는 방법에 대한 기사를 보았지만 블로그 게시물을 찾을 수 없습니다.
ypercubeᵀᴹ

이 논의는 특정 하드웨어에서 구체적인 스키마에 대해 실행되는 구체적인 워크로드가없는 경우에는 의미가 없습니다. 단조롭게 증가하는 시퀀스의 인덱스가 "핫 스팟"을 만들 것이라는 데 모두 동의 할 수 있기를 바랍니다. 허용 할 수없는 병목 현상이 발생하는지 여부와 병목 현상이 발생하는지 여부는 상황에 따라 다릅니다.
mustaccio
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.