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?Saya tidak akan mempertimbangkan pertanyaan apakah suatu indeks harus unik atau tidak, dan apakah ada biaya tambahan dalam pendekatan ini atau itu. Tetapi beberapa hal mengganggu saya dalam desain umum Anda
WHERE is_deleted = 0
) dan lihat menggunakan indeks yang difilter. Saya bahkan akan mempertimbangkan untuk menggunakan 2 indeks yang difilter, satu untukwhere is_deleted = 0
dan yang lainnya untukwhere is_deleted = 1
Pada dasarnya ini lebih mirip latihan pengkodean yang dirancang untuk menguji hipotesis daripada masalah / solusi nyata, tetapi kedua pola tersebut jelas merupakan sesuatu yang saya cari dalam ulasan kode.
sumber
Nonclustered
indeks akan memiliki kunci pengelompokan ditambahkan ke akhir baris data untuk pencarian kunci internal. Dengan demikian, kedua indeks secara fisik sama, yang merupakan poin dari pertanyaan saya.Sepertinya Anda hanya menggunakan PK untuk membuat indeks alternatif yang lebih kecil. Oleh karena itu, kinerja lebih cepat.
Anda melihat ini di perusahaan yang memiliki tabel data besar (misalnya: tabel data master). Seseorang memutuskan untuk memiliki satu indeks berkerumun besar di atasnya mengharapkannya untuk memenuhi kebutuhan berbagai kelompok pelaporan.
Tapi, satu kelompok mungkin hanya membutuhkan beberapa bagian dari indeks itu sementara kelompok lain membutuhkan bagian lain .. sehingga indeks hanya menampar di setiap kolom di bawah matahari untuk "mengoptimalkan kinerja" tidak terlalu membantu.
Sementara itu, memecahnya untuk membuat beberapa, lebih kecil, indeks bertarget, sering memecahkan masalah.
Dan, sepertinya itulah yang Anda lakukan. Anda memiliki indeks pengelompokan besar ini dengan kinerja yang buruk, maka Anda menggunakan PK untuk membuat indeks lain dengan lebih sedikit kolom yang (tidak mengejutkan) memiliki kinerja yang lebih baik.
Jadi, lakukan saja analisis dan cari tahu apakah Anda dapat mengambil indeks berkerumun tunggal dan memecahnya menjadi indeks yang lebih kecil, bertarget yang membutuhkan pekerjaan tertentu.
Anda harus menganalisis kinerja kemudian dari titik berdiri "indeks tunggal vs beberapa indeks", karena ada overhead dalam membuat dan memperbarui indeks. Tetapi, Anda harus menganalisis ini dari perspektif keseluruhan.
EG: itu mungkin kurang intensif sumber daya untuk satu indeks cluster besar, dan lebih intensif sumber daya untuk memiliki beberapa indeks target yang lebih kecil. Tetapi, jika Anda kemudian dapat menjalankan kueri yang ditargetkan di back-end lebih cepat, menghemat waktu (dan uang) di sana, mungkin itu layak dilakukan.
Jadi, Anda harus melakukan analisis end-to-end .. tidak hanya melihat bagaimana hal itu berdampak pada dunia Anda sendiri, tetapi juga bagaimana hal itu berdampak pada pengguna akhir.
Saya hanya merasa seperti Anda salah menggunakan pengidentifikasi PK. Tapi, Anda mungkin menggunakan sistem basis data yang hanya memungkinkan 1 indeks (?), Tetapi Anda dapat menyelinap masuk yang lain jika Anda PK (b / c setiap sistem basis data relasional hari ini tampaknya secara otomatis mengindeks PK). Namun, sebagian besar RDBMS modern harus memungkinkan pembuatan banyak indeks; seharusnya tidak ada batasan jumlah indeks yang dapat Anda buat (sebagai lawan dari batas 1 PK).
Jadi, dengan membuat PK yang hanya bertindak seperti indeks alt .. Anda menggunakan PK Anda, yang mungkin diperlukan jika tabel nanti diperluas dalam peran itu.
Itu tidak berarti meja Anda tidak memerlukan PK .. SOP DB 101 mengatakan "setiap meja harus memiliki PK". Tetapi, dalam situasi pergudangan data atau semacamnya .. memiliki PK di atas meja mungkin hanya overhead tambahan yang tidak Anda butuhkan. Atau, itu bisa berupa pengiriman dewa untuk memastikan Anda tidak menambahkan entri dupe ganda. Ini benar-benar masalah apa yang Anda lakukan dan mengapa Anda melakukannya.
Tapi, tabel besar pasti mendapat manfaat dari memiliki indeks. Tapi, dengan asumsi satu indeks cluster besar akan menjadi yang terbaik adalah hanya ... itu mungkin yang terbaik .. tapi saya akan merekomendasikan pengujian pada tes dan memecah indeks menjadi beberapa indeks yang lebih kecil yang menargetkan skenario kasus penggunaan tertentu.
sumber