MySQL выполняет некоторые запросы ActiveRecord медленнее, чем если бы они выполнялись напрямую (с помощью команды «mysql») - PullRequest
0 голосов
/ 05 марта 2019

У меня странное поведение ActiveRecord (возможно, в сочетании с сервером MySQL). Существует огромная таблица (сотни миллионов записей). Если я сделаю этот простой вызов:

SearchResult.where(id: ids[0..15000]).select('uid').to_a

... это займет не более 1 секунды.

Теперь, если я сделаю этот звонок:

SearchResult.where(id: ids[0..16000]).select('uid').to_a

... это может занять минуты!

Хотя в то же время, если я запускаю следующие два запроса, чтобы получить все записи по 16 тыс., Он работает ровно в течение 1 секунды:

SearchResult.where(id: ids[0..15000]).select('uid').to_a +
  SearchResult.where(id: ids[15001..16000]).select('uid').to_a

Более того, если я вызову .to_sql для длительной команды и выполню ее напрямую с помощью команды mysql или MySQL Workbench - это займет даже меньше секунды.

Я запустил ANALYZE TABLE, а затем попробовал EXPLAIN как напрямую, так и через ActiveRecord, и они идентичны. В обоих случаях используется ВСЕ сканирование (полное сканирование таблицы). Разница лишь в том, что он работает хорошо напрямую, но зависает при выполнении через ActiveRecord. Теперь самое интересное - если я заставлю использовать индекс PRIMARY - он начнет хорошо работать через ActiveRecord, но это не решение, потому что я не могу использовать его с предварительной загрузкой ассоциаций ActiveRecord.

Это странное поведение действительно ставит меня в тупик, потому что я использую много предварительных загрузок ассоциаций ActiveRecord (например, .includes(searches: :search_results)), которые иногда заканчивают запросом десятков тысяч записей (да, мне действительно все они нужны), и тому подобное Запрос останавливается на несколько минут. Я бы просто использовал принудительное использование индекса, но это не решает проблему в других местах, создает больше проблем в других, и тогда я не смогу использовать предварительную загрузку ActiveRecord. Есть идеи?

1 Ответ

2 голосов
/ 05 марта 2019

Может быть, это не SQL, а создание экземпляров SearchResult.
Если вас интересует только uid, попробуйте

SearchResult.where(id: ids[0..16000]).pluck(:uid)

возвращает массив uids, а не массив SearchResults.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...