저의 SQL (Server 2008)에 대한 저수준 지식은 제한적이며 이제 DBA가 문제를 해결하고 있습니다. 시나리오를 설명해 드리겠습니다 (내가 옳다는 희망으로 명백한 진술을 언급했지만 잘못된 것을 발견하면 알려주세요).
사람들을위한 ‘법원 명령’을 보관하는 테이블이 있습니다. (이름 : CourtOrder) 테이블을 만들 때 다음과 같이 만들었습니다.
CREATE TABLE dbo.CourtOrder
(
CourtOrderID INT NOT NULL IDENTITY(1,1), (Primary Key)
PersonId INT NOT NULL,
+ around 20 other fields of different types.
)
그런 다음 효율성을 위해 클러스터되지 않은 인덱스를 기본 키에 적용했습니다. 내 이유는 이것이 고유 한 필드 (기본 키)이고 주로 선택 목적으로 인덱싱되어야하기 때문입니다.Select from table where primary key = ...
그런 다음 PersonId에 CLUSTERED 인덱스를 적용했습니다. 그 이유는 대부분의 작업이 한 사람에 대한 주문을 받고 있기 때문에 특정 사람에 대한 주문을 물리적으로 그룹화하기 때문입니다. 그래서,select from mytable where personId = ...
나는 지금 이것에 대해 뽑혔다. 클러스터형 인덱스는 기본 키에, 일반 인덱스는 personId에 배치해야한다고 들었습니다. 그것은 나에게 매우 이상하게 보입니다. 우선, 고유 한 열에 클러스터형 인덱스를 배치하는 이유는 무엇입니까? 클러스터링이란 무엇입니까? 확실히 클러스터형 인덱스의 낭비입니까? 고유 한 열에 일반 인덱스가 사용된다고 믿었을 것입니다. 또한 인덱스 클러스터링은 다른 열을 클러스터링 할 수 없음을 의미합니다 (테이블 당 하나, 맞습니까?).
내가 실수했다는 이유는 PersonId에 클러스터형 인덱스를 넣으면 삽입 속도가 느려질 것이라고 믿기 때문입니다. 선택 속도가 5 % 증가하면 삽입 및 업데이트 속도가 95 % 저하됩니다. 정확하고 유효합니까?
personId를 클러스터링하기 때문에 SQL Server는 PersonId를 삽입하거나 변경할 때마다 데이터를 재 배열해야한다고 말합니다.
그래서 나는 왜 그렇게 느리다면 SQL이 CLUSTERED INDEX의 개념을 가질까요? 그들이 말하는 것만 큼 느린가요? 최적의 성능을 얻으려면 인덱스를 어떻게 설정해야합니까? SELECT가 INSERT보다 더 많이 사용된다고 생각했지만 INSERTS에 잠금 문제가 있다고 말합니다.
누군가 나를 도울 수 있기를 바랍니다.
답변
클러스터형 인덱스와 비 클러스터형 인덱스의 차이점은 클러스터형 인덱스가 데이터베이스 행의 물리적 순서를 결정한다는 것 입니다. 즉, 클러스터형 인덱스를에 적용하면 PersonId
행이 PersonId
테이블에서 물리적으로 정렬 되어 이에 대한 인덱스 검색이 행으로 바로 이동할 수 있습니다 (비 클러스터형 인덱스가 아닌 행의 위치, 추가 단계 추가).
즉, 기본 키가 클러스터 된 인덱스가 아니라 전례가없는 경우는 드뭅니다 . 시나리오의 문제는 실제로 가정하는 것과 반대입니다 . 중복이 아닌 클러스터형 인덱스에서 고유 한 값 을 원합니다 . 클러스터형 인덱스는 행의 물리적 순서를 결정하기 때문에 인덱스가 고유하지 않은 열에있는 경우 서버는 중복 키 값이있는 행 (귀하의 경우 동일한 값을 가진 행)에 배경 값을 추가해야합니다. PersonId
) 결합 된 값 (키 + 배경 값)이 고유하도록합니다.
내가되는 제안 유일한 것은 하지 대리 키 (사용자의 사용 CourtOrderId
대신 기본 키 등) 열,하지만의 복합 기본 키를 사용하여 PersonId
열 및 일부 다른 고유 식별 열 또는 세트를. 그래도 가능하지 않거나 실용적이지 않은 경우 클러스터형 인덱스를 CourtOrderId
.
답변
나는 결코 SQL 전문가가 아니므로 DBA 관점이 아닌 개발자 관점으로 생각하십시오 ..
순차적 순서가 아닌 클러스터 된 (물리적으로 정렬 된) 인덱스에 대한 삽입은 삽입 / 업데이트에 대한 추가 작업을 유발합니다. 또한 한 번에 많은 삽입이 발생하고 모두 동일한 위치에서 발생하는 경우 경합이 발생합니다. 특정 성능은 데이터 및 액세스 방법에 따라 다릅니다. 일반적인 경험 규칙은 테이블에서 가장 고유 한 좁은 값 (일반적으로 PK)에 클러스터형 인덱스를 구축하는 것입니다.
PersonId가 변경되지 않을 것이라고 가정하므로 여기에서 업데이트가 작동하지 않습니다. 그러나 PersonId가 1 2 3 3 4 5 6 7 8 8 인 몇 행의 스냅 샷을 고려하십시오.
이제 3의 PersonId에 대해 20 개의 새 행을 삽입합니다. 먼저 이것은 고유 키가 아니기 때문에 서버는 값에 약간의 추가 바이트를 추가하여 (장면 뒤에서) 고유하게 만들고 (추가 공간도 추가 함) 위치를 지정합니다. 이것들은 상주 할 것입니다. 삽입이 끝에 발생하는 자동 증가 PK 삽입과 비교하십시오. 비 기술적 인 설명은 다음과 같을 것입니다. 테이블 끝에서 더 높은 값이 자연스럽게 진행되고 항목을 삽입하는 동안 해당 위치에서 기존 항목의 위치를 재 작업하는 경우 수행 할 ‘리프 셔플 링’작업이 적습니다.
이제 삽입에 문제가있는 경우 동일한 (또는 유사한) PersonId 값을 한 번에 삽입하여 테이블 전체의 다양한 위치에서이 추가 작업을 유발하고 조각화로 인해 죽을 가능성이 있습니다. 귀하의 경우 클러스터링되는 PK로 전환하는 단점은 테이블 전체에 분산 된 값이 다른 PersonIds에 삽입 문제가있는 경우, 클러스터형 인덱스를 PK로 전환하고 모든 삽입이 이제 하나에서 발생하는 경우입니다. 경합 집중 증가로 인해 문제가 실제로 악화 될 수 있습니다. (반대로, 오늘날 삽입물이 전체적으로 퍼져 있지 않지만 일반적으로 모두 유사한 영역에 묶여 있다면 클러스터형 인덱스를 PersonId에서 PK로 전환하여 문제를 완화 할 수 있습니다. 분열.)
성능 문제는 고유 한 상황에 따라 분석되어야하며 이러한 유형의 답변은 일반적인 지침으로 만 사용하십시오. 최선의 방법은 문제가 어디에 있는지 정확히 확인할 수있는 DBA에 의존하는 것입니다. 단순한 인덱스 조정 이상의 리소스 경합 문제가있는 것 같습니다. 이것은 훨씬 더 큰 문제의 증상 일 수 있습니다. (아마도 디자인 문제 … 그렇지 않으면 리소스 제한이 있습니다.)
어쨌든 행운을 빕니다!
답변
일부 작성자는 범위 쿼리에 도움이되는 대안이있는 경우 열 CI
에서 “을 낭비”하지 말 것을 제안 identity
합니다.
MSDN Clustered Index Design Guidelines 에서 다음 기준에 따라 키를 선택해야합니다.
- 자주 사용하는 쿼리에 사용할 수 있습니다.
- 높은 수준의 고유성을 제공합니다.
- 범위 쿼리에 사용할 수 있습니다.
귀하의 CourtOrderID
열은 만족 2
. 당신은 PersonId
만족 1
하고 3
. uniqueifier
어쨌든 대부분의 행은 추가 된 것으로 끝날 것이므로 고유 한 것으로 선언 PersonId,CourtOrderID
하고 동일한 너비를 사용하지만 클러스터형 인덱스 키가 행 로케이터로 모든 NCI에 추가되므로 더 유용합니다. 더 많은 쿼리를 처리합니다.
PersonId,CourtOrderID
CI 로 사용할 때 의 주요 문제 는 논리적 조각화가 발생할 가능성이 있으므로 (특히 도움을 주려는 범위 쿼리에 영향을 미침) 채우기 비율과 조각화 수준을 모니터링하고 인덱스 유지 관리를 더 자주 수행해야한다는 것입니다.
답변
다음 링크에 설명되어 있습니다. https://msdn.microsoft.com/en-us/ms190457.aspx
클러스터링
-
클러스터형 인덱스 는 키 값을 기반으로 테이블 또는 뷰의 데이터 행을 정렬하고 저장 합니다. 인덱스 정의에 포함 된 열입니다. 데이터 행 자체는 하나의 순서로만 정렬 할 수 있으므로 테이블 당 하나의 클러스터형 인덱스 만있을 수 있습니다.
-
테이블의 데이터 행이 정렬 된 순서로 저장되는 유일한 경우는 테이블에 클러스터형 인덱스가 포함 된 경우입니다. 테이블에 클러스터형 인덱스가있는 경우 해당 테이블을 클러스터형 테이블이라고합니다. 테이블에 클러스터형 인덱스가없는 경우 데이터 행은 힙이라고하는 정렬되지 않은 구조에 저장됩니다.
비 클러스터
-
비 클러스터형 인덱스는 데이터 행과 별도의 구조를 갖습니다. 비 클러스터형 인덱스 는 비 클러스터형 인덱스 키 값을 포함하며 각 키 값 항목에는 키 값이 포함 된 데이터 행에 대한 포인터가 있습니다 .
-
비 클러스터형 인덱스의 인덱스 행에서 데이터 행으로의 포인터를 행 로케이터라고합니다. 행 로케이터의 구조는 데이터 페이지가 힙 또는 클러스터 된 테이블에 저장되는지 여부에 따라 다릅니다. 힙의 경우 행 로케이터는 행에 대한 포인터입니다. 클러스터 된 테이블의 경우 행 로케이터는 클러스터 된 인덱스 키입니다.
-
비 클러스터형 인덱스의 리프 수준에 키가 아닌 열을 추가하여 기존 인덱스 키 제한 (900 바이트 및 16 개 키 열)을 무시하고 완전히 포함 된 인덱싱 된 쿼리를 실행할 수 있습니다.
답변
일부 불쾌한 선택이있는 일부 db, 저장 프로 시저에 조인-차이점 만 인덱스입니다.
INDEXES-클러스터형 vs 비 클러스터형
891 rows
10 sec
NONCLUSTERED
OR
891 rows
14 sec
CLUSTERED