인덱스 비용 및 고유성이 유익한 지 아닌지 (아마도 둘 다)에 대해 사무실의 여러 개발자와 토론을 진행하고 있습니다. 문제의 핵심은 경쟁 리소스입니다.
배경
나는 이전에 언급 한 토론을 읽었습니다. Unique
인덱스가 유지 관리에 추가 비용이 들지 않는다는Insert
작업이 B- 트리에 맞는 위치를 암시 적으로 확인하고 고유하지 않은 인덱스에서 중복이 발견되면 유니티를 추가하기 때문에 키의 끝이지만 직접 삽입합니다. 이 일련의 이벤트에서 Unique
인덱스는 추가 비용이 없습니다.
저의 동료 Unique
는 B- 트리에서 새로운 위치를 찾은 후 두 번째 작업으로 시행되므로 고유하지 않은 인덱스보다 유지 관리 비용이 더 많이 든다는 말을 통해이 진술에 맞서고 있습니다.
최악의 경우, 테이블의 클러스터링 키인 식별 컬럼 (내재적으로 고유)이있는 테이블을 보았지만 고유하지 않은 것으로 명시되었습니다. 최악의 다른 측면에는 고유성에 대한 집착이 있으며 모든 인덱스는 고유 한 것으로 생성되며 인덱스와 명시 적으로 고유 한 관계를 정의 할 수없는 경우 인덱스의 끝에 테이블의 PK를 추가하여 독창성이 보장됩니다.
개발자 팀의 코드 검토에 자주 참여하며 따라야 할 일반적인 지침을 제공 할 수 있어야합니다. 예, 모든 인덱스를 평가해야하지만 테이블에 각각 수천 개의 테이블이 있고 5 개의 서버가 있고 20 개의 인덱스가있는 경우 특정 수준의 품질을 보장하기 위해 몇 가지 간단한 규칙을 적용 할 수 있어야합니다.
질문
고유성이 Insert
아닌 인덱스를 유지하는 비용과 비교하여 백엔드에 추가 비용이 있습니까? 둘째, 고유성을 보장하기 위해 인덱스 끝에 테이블의 기본 키를 추가하는 데 어떤 문제가 있습니까?
테이블 정의 예
create table #test_index
(
id int not null identity(1, 1),
dt datetime not null default(current_timestamp),
val varchar(100) not null,
is_deleted bit not null default(0),
primary key nonclustered(id desc),
unique clustered(dt desc, id desc)
);
create index
[nonunique_nonclustered_example]
on #test_index
(is_deleted)
include
(val);
create unique index
[unique_nonclustered_example]
on #test_index
(is_deleted, dt desc, id desc)
include
(val);
예
Unique
인덱스 끝에 키를 추가하는 이유 는 팩트 테이블 중 하나에 있습니다. 있다 Primary Key
입니다 Identity
열입니다. 그러나 Clustered Index
대신 파티션 구성표 열 뒤에 고유성이없는 3 개의 외래 키 차원이옵니다. 이 테이블의 선택 성능은 끔찍하며을 Primary Key
활용하는 대신 키 조회를 사용하여 검색 시간을 늘리는 것이 좋습니다 Clustered Index
. 비슷한 디자인을 따르지만 Primary Key
끝에 추가 된 다른 테이블의 성능은 상당히 향상되었습니다.
-- date_int is equivalent to convert(int, convert(varchar, current_timestamp, 112))
if not exists(select * from sys.partition_functions where [name] = N'pf_date_int')
create partition function
pf_date_int (int)
as range right for values
(19000101, 20180101, 20180401, 20180701, 20181001, 20190101, 20190401, 20190701);
go
if not exists(select * from sys.partition_schemes where [name] = N'ps_date_int')
create partition scheme
ps_date_int
as partition
pf_date_int all
to
([PRIMARY]);
go
if not exists(select * from sys.objects where [object_id] = OBJECT_ID(N'dbo.bad_fact_table'))
create table dbo.bad_fact_table
(
id int not null, -- Identity implemented elsewhere, and CDC populates
date_int int not null,
dt date not null,
group_id int not null,
group_entity_id int not null, -- member of group
fk_id int not null,
-- tons of other columns
primary key nonclustered(id, date_int),
index [ci_bad_fact_table] clustered (date_int, group_id, group_entity_id, fk_id)
)
on ps_date_int(date_int);
go
if not exists(select * from sys.objects where [object_id] = OBJECT_ID(N'dbo.better_fact_table'))
create table dbo.better_fact_table
(
id int not null, -- Identity implemented elsewhere, and CDC populates
date_int int not null,
dt date not null,
group_id int not null,
group_entity_id int not null, -- member of group
-- tons of other columns
primary key nonclustered(id, date_int),
index [ci_better_fact_table] clustered(date_int, group_id, group_entity_id, id)
)
on ps_date_int(date_int);
go
Case
과If
구조가 10 레벨로 제한되는 것과 마찬가지로 고유하지 않은 엔터티를 해결하는 데 제한이 있다는 것도 의미가 있습니다. 귀하의 진술에 따르면, 이는 클러스터링 키가 고유하지 않은 경우에만 적용되는 것처럼 들립니다. 이것이Nonclustered Index
클러스터링 키Unique
에 문제가Nonclustered
있습니까, 아니면 인덱스에 문제가 없습니까?