【发布时间】:2019-03-05 14:44:56
【问题描述】:
我有一个奇怪的 ActiveRecord 行为(可能与 MySQL 服务器一起使用)有一个巨大的表(数亿个条目)如果我进行这个简单的调用:
SearchResult.where(id: ids[0..15000]).select('uid').to_a
...这将花费不到 1 秒的时间。
现在如果我打这个电话:
SearchResult.where(id: ids[0..16000]).select('uid').to_a
...可能需要几分钟!
同时,如果我运行以下两个查询以获取所有 16k 条目 - 它总共在 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,然后直接和通过 ActiveRecord 尝试了 EXPLAIN,它们是相同的。两者虽然都使用ALL scan(全表扫描),唯一的区别是直接执行的很好,但是通过ActiveRecord执行的时候就挂了。现在有趣的是 - 如果我强制使用 PRIMARY 索引 - 它开始通过 ActiveRecord 正常工作,但这不是一个解决方案,因为我不能将它与 ActiveRecord 关联预加载一起使用。
这种奇怪的行为真的让我很困扰,因为我使用了大量的 ActiveRecord 关联预加载(例如 .includes(searches: :search_results)),有时最终会请求成千上万条记录(是的,我确实需要所有记录)等等查询停止执行好几分钟。我只会强制使用索引,但它不能解决其他地方的问题,会在其他地方造成更多问题,而且我将无法使用 ActiveRecord 预加载。有什么想法吗?
【问题讨论】:
-
ids数组由什么组成?重新考虑您的查询模式以使用子查询或范围可能更有意义。一个Array值将创建一个IN子句,一个Range值将创建一个BETWEEN子句,使用不同的ActiveRecord::Relation将创建一个子查询。
标签: mysql ruby-on-rails activerecord