При работе с большими таблицами иногда возникают ситуации, когда простой запрос начинает выполняться очень медленно.
В этой заметке рассмотрим реальный кейс оптимизации запроса в Yii2, где добавление LIMIT 1 неожиданно резко ускорило выборку.
Есть таблица транзакций: transaction_log. Размер таблицы — несколько миллионов записей.
Структура упрощённо выглядит так:
Также существует индекс:
Задача получить последнюю транзакцию организации.
В Yii2 это выглядело так:
Проблема заключалась в том, что у некоторых организаций в таблице накопилось более 2 миллионов записей. Запрос начал выполняться очень долго, иногда приводя к таймауту страницы.
Сгенерированный SQL выглядел так:
Обратите внимание — ограничения на количество строк нет. Хотя в PHP используется one(), на уровне SQL серверу всё равно приходится:
1. Найти все строки организации
2. Отсортировать их
3. Вернуть результат
Для миллионов строк это может быть очень дорого.
Было добавлено явное ограничение:
После этого Yii2 сгенерировал другой запрос:
Запрос стал выполняться значительно быстрее.
Почему это работает?
В SQL Server оптимизатор начинает применять так называемый Row Goal Optimization. Это означает: Оптимизатор понимает, что нужна только одна строка, и старается найти её максимально быстро.
В результате:
• уменьшается объём читаемых данных
• может использоваться более эффективный план выполнения
• сортировка большого объёма данных может быть частично или полностью устранена
Почему one() не помог
Метод one() в Yii2:
• ограничивает количество возвращаемых результатов на уровне ActiveRecord
• но не всегда заставляет SQL генератор добавить TOP 1 или FETCH NEXT 1 В результате SQL Server не знает, что нужно только одна строка.
Когда это особенно важно? Эта оптимизация полезна, если:
• таблица очень большая
• у одного ключа может быть много записей
• используется ORDER BY
• требуется только одна запись
При использовании Yii2 с SQL Server для выборки одной записи из больших таблиц лучше писать:
Иногда небольшое изменение в ORM-запросе может существенно повлиять на план выполнения SQL. Если запрос выбирает одну строку из потенциально большого набора, явное использование LIMIT 1 может значительно ускорить выполнение.



