Что делать, если запрос не использует индексы
Что проверяют
Понимаете ли вы, какой именно SQL уходит в базу из вашего кода, и умеете ли читать план выполнения. Для разработчика на .NET это ещё и вопрос про ORM: половина таких историй начинается с неудачного запроса на LINQ.
Как отвечать
Начинать не с догадок, а с фактов: снять фактический план выполнения и включить статистику ввода-вывода, чтобы увидеть логические чтения. Если запрос приходит из ORM, сначала посмотреть сгенерированный SQL через логирование: оптимизировать по коду на C# бессмысленно.
Типичные причины, по которым индекс не берётся:
- функция или приведение типа поверх колонки. Условие
WHERE YEAR(d) = 2022переписывается диапазономd >= '2022-01-01' AND d < '2023-01-01'; - неявное приведение типов. Классика: в модели свойство
string, в базе колонкаvarchar, параметр уезжает какnvarchar, и вместо поиска получается сканирование. Лечится явным указанием типа колонки в маппинге; - поиск подстроки вида
LIKE '%x%'. Шаблон с началом строки индекс использует, поиск в середине нет; - индекс не покрывающий. Оптимизатор считает, что просканировать таблицу дешевле, чем обращаться к строке за каждой недостающей колонкой. Помогает
INCLUDEили выборка проекции вместо всей сущности; - порядок колонок в составном индексе: фильтр по второй колонке без первой поиска по индексу не даст;
- устаревшая статистика и попавшее в кэш плохое значение параметра.
Где спотыкаются
Отвечают «добавлю индекс», не открыв план. Лишний индекс замедляет вставку и обновление, а причину вроде функции над колонкой не устраняет вовсе.
Оптимизируют не тот запрос. Материализация коллекции в памяти до фильтрации превращает условие в клиентское: база честно отдаёт всю таблицу, и в фактическом запросе нет никакого WHERE.
Прибивают план подсказкой оптимизатору вместо устранения причины. Такой запрос живёт ровно до следующего роста данных, а потом ломается уже без возможности выбрать план получше.