У мене в офісі тривають дискусії з різними розробниками про вартість індексу, і про те, чи є унікальність корисною чи дорогою (напевно, обидва). Суть проблеми - наші конкуруючі ресурси.
Фон
Раніше я читав дискусію, яка заявляє, що Unique
індекс не потребує додаткових витрат на підтримання, оскільки Insert
операція неявно перевіряє, куди він вписується у B-дерево, і, якщо дублікат знайдений у не унікальному індексі, додає унікатор до кінець ключа, але в іншому випадку вставляється безпосередньо. У цій послідовності подій, aUnique
індекс не має додаткових витрат.
Мій колега бореться з цим твердженням, кажучи, що Unique
виконується як друга операція після прагнення до нової позиції в B-дереві, і, таким чином, дорожче підтримувати, ніж не унікальний індекс.
У гіршому випадку я бачив таблиці зі стовпчиком ідентичності (за своєю суттю унікальною), що є кластеризованим ключем таблиці, але явно зазначеним як не унікальний. З іншого боку найгірше - моя одержимість унікальністю, і всі індекси створюються як унікальні, і коли неможливо визначити явно унікальне відношення до індексу, я додаю ПК таблиці до кінця індексу, щоб забезпечити унікальність гарантована.
Я часто беру участь у перегляді кодів для команди розробників, і мені потрібно мати можливість дати загальні вказівки щодо їх виконання. Так, кожен індекс повинен бути оцінений, але коли у вас є п'ять серверів з тисячами таблиць кожен і цілих двадцять індексів на столі, вам потрібно вміти застосовувати кілька простих правил, щоб забезпечити певний рівень якості.
Питання
Чи має унікальність додаткові витрати на задньому плані 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
натомість стовпець схеми розподілу розміщений після чого три зовнішні ключові розміри без унікальності. Вибір продуктивності в цій таблиці є ненормальним, і я часто отримую кращі пошуки часів, використовуючи 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
індексами?