Saya telah memiliki perdebatan yang sedang berlangsung dengan berbagai pengembang di kantor saya tentang biaya indeks, dan apakah keunikan itu bermanfaat atau mahal (mungkin keduanya). Inti dari masalah ini adalah sumber daya kita yang bersaing.
Latar Belakang
Saya sebelumnya telah membaca sebuah diskusi yang menyatakan Unique
indeks bukan biaya tambahan untuk mempertahankan, karena Insert
operasi secara implisit memeriksa di mana itu cocok dengan B-tree, dan, jika duplikat ditemukan dalam indeks non-unik, menambahkan uniquifier ke akhir kunci, tetapi jika tidak memasukkan secara langsung. Dalam urutan peristiwa ini, Unique
indeks tidak memiliki biaya tambahan.
Rekan kerja saya memerangi pernyataan ini dengan mengatakan bahwa Unique
diberlakukan sebagai operasi kedua setelah mencari posisi baru di B-tree, dan dengan demikian lebih mahal untuk mempertahankannya daripada indeks yang tidak unik.
Paling buruk, saya telah melihat tabel dengan kolom identitas (inheren unik) yang merupakan kunci pengelompokan tabel, tetapi secara eksplisit dinyatakan sebagai non-unik. Di sisi lain yang terburuk adalah obsesi saya terhadap keunikan, dan semua indeks dibuat unik, dan ketika tidak mungkin untuk mendefinisikan hubungan unik yang eksplisit dengan indeks, saya menambahkan PK tabel ke akhir indeks untuk memastikan Keunikan dijamin.
Saya sering terlibat dalam ulasan kode untuk tim dev, dan saya harus bisa memberikan panduan umum agar mereka ikuti. Ya, setiap indeks harus dievaluasi, tetapi ketika Anda memiliki lima server dengan ribuan tabel masing-masing dan sebanyak dua puluh indeks pada sebuah tabel, Anda harus dapat menerapkan beberapa aturan sederhana untuk memastikan tingkat kualitas tertentu.
Pertanyaan
Apakah keunikan memiliki biaya tambahan di belakang Insert
dibandingkan dengan biaya mempertahankan indeks yang tidak unik? Kedua, apa yang salah dengan menambahkan Kunci Utama dari tabel sampai akhir indeks untuk memastikan keunikan?
Contoh Definisi Tabel
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);
Contoh
Contoh mengapa saya akan menambahkan Unique
kunci pada akhir indeks ada di salah satu tabel fakta kami. Ada Primary Key
yang merupakan Identity
kolom. Namun, Clustered Index
itu bukan kolom skema partisi, diikuti oleh tiga dimensi kunci asing tanpa keunikan. Pilih kinerja pada tabel ini sangat buruk, dan saya sering mendapatkan waktu mencari yang lebih baik menggunakan Primary Key
pencarian kunci daripada memanfaatkannya Clustered Index
. Tabel lain yang mengikuti desain yang serupa, tetapi Primary Key
ditambahkan sampai akhir memiliki kinerja yang jauh lebih baik.
-- 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
danIf
struktur dibatasi hingga 10 level, masuk akal bahwa ada juga batas untuk menyelesaikan entitas yang tidak unik. Dengan pernyataan Anda, ini sepertinya hanya berlaku untuk kasus-kasus ketika kunci pengelompokan tidak unik. Apakah ini masalah untukNonclustered Index
atau jika kunci clusteringUnique
maka tidak ada masalah untukNonclustered
indeks?