Какие индексы разумно ставить на числовые и строковые поля в базе данных
Что проверяют
Понимаете ли вы, что тип данных влияет на индекс: размер ключа, сравнение строк, селективность. Для C# это чаще всего SQL Server и EF Core, поэтому ждут знания их поведения по умолчанию. Следом спрашивают, почему индекс по строке не сработал на LIKE.
Как отвечать
Числовые поля:
- первичный ключ: в SQL Server он по умолчанию становится кластерным индексом. Узкий возрастающий
intилиbigintхорош, случайныйGuidведёт к расщеплению страниц, поэтому берутNEWSEQUENTIALID()или последовательные GUID из приложения; - внешние ключи: SQL Server сам их не индексирует, а индекс нужен под
JOINи каскадное удаление. EF Core в миграциях создаёт его по соглашению; - диапазоны и сортировка: даты, суммы, счётчики хорошо ложатся в обычный индекс, в составном ставятся после колонок с равенством.
Строковые поля:
- размер ключа: предел ключа некластерного индекса 1700 байт,
nvarchar(max)ключом быть не может, только вINCLUDE. Поэтому EF Core мапит индексируемую строку безHasMaxLengthвnvarchar(450); - регистр: коллация по умолчанию обычно нечувствительна к регистру,
WHERE Email = @emailработает безLOWER, аLOWER(Email)в условии как раз ломает seek; - LIKE:
'abc%'даёт seek,'%abc%'читает весь индекс. Для поиска по словам есть Full-Text Search сCONTAINS; - низкая селективность: статус или флаг закрывают фильтрованным индексом по редкому значению;
- уникальность: email, логин, артикул закрепляют уникальным индексом, это ещё и защита от дублей.
Где спотыкаются
Не следят за varchar и nvarchar. Колонка varchar, а EF Core шлёт параметр как nvarchar: SQL Server преобразует колонку и часто вместо seek делает scan. Лечится IsUnicode(false) в модели.
Хранят числа строками: коды, номера, суммы. Сравнение становится лексикографическим, '10' < '9', и диапазонные запросы ломаются.
Ставят индекс на каждую колонку «на всякий случай» и получают медленную запись, хотя планировщик использует пару из них.