В моем офисе ведутся постоянные дебаты о стоимости индекса, а также о том, является ли уникальность выгодной или дорогой (вероятно, и то и другое). Суть проблемы - наши конкурирующие ресурсы.
Фон
Ранее я читал обсуждение, в котором говорилось, что Unique
индекс не требует дополнительных затрат на поддержание, поскольку Insert
операция неявно проверяет, подходит ли она к B-дереву, и, если дубликат найден в неуникальном индексе, добавляет к ним уникальный код конец ключа, но в противном случае вставляется напрямую. В этой последовательности событий Unique
индекс не имеет дополнительных затрат.
Мой коллега борется с этим утверждением, говоря, что он Unique
выполняется как вторая операция после поиска новой позиции в B-дереве и, следовательно, более дорогостоящий в обслуживании, чем неуникальный индекс.
В худшем случае я видел таблицы со столбцом идентификаторов (изначально уникальным), который является ключом кластеризации таблицы, но явно указан как неуникальный. С другой стороны, хуже всего - моя одержимость уникальностью, и все индексы создаются как уникальные, и когда невозможно определить явно уникальную связь с индексом, я добавляю PK таблицы в конец индекса, чтобы обеспечить Уникальность гарантирована.
Я часто участвую в обзорах кода для команды разработчиков, и мне нужно дать общие рекомендации, которым они должны следовать. Да, каждый индекс должен оцениваться, но когда у вас есть пять серверов с тысячами таблиц на каждом и целых двадцать индексов в таблице, вам необходимо иметь возможность применять некоторые простые правила для обеспечения определенного уровня качества.
Вопрос
Есть ли у уникальности дополнительные расходы на бэкэнд по 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
индексов?