SQL-сервер - стоит индексировать большие строковые ключи?
У меня есть таблица с большим строковым ключом (varchar(1024)), который я собирался проиндексировать на сервере SQL (я хочу иметь возможность быстрого поиска по нему, но также важны вставки). В SQL 2008 я не получаю предупреждение об этом, но в SQL Server 2005 он сообщает мне, что он превышает 900 байт и что вставки / обновления столбца с таким размером будут отброшены (или что-то в этой области)
Каковы мои альтернативы, если я хочу индексировать этот большой столбец? Я не знаю, стоило ли бы это того, если бы я мог так или иначе.
2 ответа
Индекс со всеми ключами около 900 байт будет очень большим и очень глубоким (очень мало ключей на страницу приводит к очень высоким B-деревьям).
Это зависит от того, как вы планируете запрашивать значения. Индекс полезен в нескольких случаях:
- когда значение проверяется. Это наиболее типичное использование, когда в таблице ищется точное значение. Типичные примеры
WHERE column='ABC'
или условие соединенияON a.column = B.someothercolumn
, - когда диапазон сканируется. Это также довольно типично при поиске диапазона значений в таблице. Помимо очевидного примера
WHERE column BETWEEN 'ABC' AND 'DEF'
Есть и другие, менее очевидные примеры, такие как частичное совпадение:WHERE column LIKE 'ABC%'
, - требование заказа. Это использование менее известно, но индексы могут помочь запросу, который имеет явный
ORDER BY column
Требование избегать сортировки по принципу "останови и работай", а также может помочь определенному скрытомуROW_NUMBER() OVER (ORDER BY column)
,
Итак, зачем вам индекс? Какие запросы будут использовать это?
Для сканирования диапазона и для требований заказа нет другого решения, кроме как иметь индекс, и вам придется взвесить стоимость индекса и выгоды.
Для проб можно потенциально использовать хеш, чтобы избежать индексации очень большого столбца. Создать постоянный вычисляемый столбец как column_checksum = CHECKSUM(column)
а затем индексировать по этому столбцу. Запросы должны быть переписаны для использования WHERE column_checksum = CHECKSUM('ABC') AND column='ABC'
, Тщательное рассмотрение должно быть уделено взвешиванию преимущества узкого индекса (32-битной контрольной суммы) по сравнению с недостатками двойной проверки столкновения и отсутствием возможностей сканирования диапазона и порядка.
после комментария
Однажды у меня была похожая проблема, и я использовал хэш-столбец. Значение было слишком велико для индекса (>1 КБ), и мне также нужно было преобразовать значение в идентификатор для хранения (в основном, словарь). Нечто подобное:
create table values_dictionary (
id int not null identity(1,1),
value varchar(8000) not null,
value_hash = checksum(value) persisted,
constraint pk_values_dictionary_id
primary key nonclustered (id));
create unique clustered index cdx_values_dictionary_checksum on (value_hash, id);
go
create procedure usp_get_or_create_value_id (
@value varchar(8000),
@id int output)
begin
declare @hash = CHECKSUM(@value);
set @id = NULL;
select @id = id
from table
where value_hash = @hash
and value = @value;
if @id is null
begin
insert into values_dictionary (value)
values (@value);
set @id = scope_identity();
end
end
В этом случае таблица словаря организована в виде кластерного индекса на values_hash
столбец, который группирует все сталкивающиеся хеш-значения вместе. id
Добавлен столбец, чтобы сделать кластеризованный индекс уникальным, избегая необходимости в скрытом столбце уникализатора. Эта структура делает поиск для @value
максимально эффективно, без крайне неэффективного индекса на value
и минуя ограничение в 900 символов. Первичный ключ на id
не кластеризовано, что означает, что глядя вверх value
от и id
несет накладные расходы одного дополнительного зонда в кластеризованном индексе.
Не уверен, что это решит вашу проблему, вы, очевидно, знаете больше о ваших реальных сценариях, чем я. Кроме того, код не обрабатывает ошибки и может фактически вставлять повторяющиеся записи @value, что может быть или не быть правильным.
Общие рекомендации по разработке индекса
При разработке индекса учитывайте следующие рекомендации для столбцов:
Длина ключа индекса должна быть короткой для кластерных индексов. Кроме того, кластерные индексы выигрывают от создания уникальных или ненулевых столбцов. Для получения дополнительной информации см. Рекомендации по проектированию кластерного индекса.
Столбцы с типами данных ntext, text, image, varchar(max), nvarchar(max) и varbinary(max) нельзя указывать в качестве столбцов ключа индекса. Однако типы данных varchar(max), nvarchar(max), varbinary(max) и xml могут участвовать в некластеризованном индексе как столбцы неключевого индекса. Для получения дополнительной информации см. Индекс с включенными столбцами.
Изучите распределение данных в столбце. Часто длительный запрос вызывается индексацией столбца с несколькими уникальными значениями или выполнением объединения для такого столбца. Это фундаментальная проблема с данными и запросами, и, как правило, ее невозможно решить без выявления этой ситуации. Например, физический телефонный справочник, отсортированный в алфавитном порядке по фамилии, не ускорит поиск человека, если все люди в городе будут названы Смит или Джонс