ruby-on-rails - Rails 会自动优化查询吗

标签 ruby-on-rails postgresql optimization rails-activerecord

运行两个类似的查询后

@articles = @magazine.articles.limit(2).offset(0)
@articles = @articles.limit(2).offset(2)

我期望在我的控制台中看到服务器正在执行的两个 SQL 语句。但是,缺少第一个查询,只有第二个正在运行。同样,执行以下两个查询后:

@articles = @magazine.articles.limit(2).offset(0)
@articles = @articles.limit(2).offset(@articles.size - 2)

第一个查询也被完全忽略。这两个查询生成 SQL:

SELECT COUNT(count_column) FROM (SELECT  1 AS count_column FROM "articles"  
WHERE "articles"."magazine_id" = $1 LIMIT 2 OFFSET 0)
subquery_for_count  [["magazine_id", 1]]

SELECT  "articles".* FROM "articles"  
WHERE "articles"."magazine_id" = $1 
LIMIT 2 OFFSET 2  [["magazine_id", 1]]

有趣的是,如果我将 @articles.size 更改为 @articles.length,两个查询都会按预期运行。我想因为 length 需要内存中的集合,所以第一个语句被强制运行。任何人都可以描述这里发生的事情吗?如果它的主题太宽泛,请指出一个好的资源。

最佳答案

与其说是优化,不如说是将查询的执行推迟到真正需要执行它时。

在这两种情况下,您都将构建查询的结果存储在@articles 中。 Active Record,或者更准确地说是 arel,推迟查询的执行,直到您调用需要结果的方法。我怀疑当您调用类似 @articles.each@articles.count 或类似内容时,您实际上看到了针对数据库执行的查询。

您可以通过一系列步骤构建查询,但实际上不会执行:

a = @magazine.articles
a = a.limit(2)
a = a.offset(0)

这也意味着您可以在过程结束时留下一些大大减小结果大小的查询子句:

a = a.where('created_at > ?', Time.now.at_beginning_of_day)

仍然没有查询发送到数据库。

需要注意的是在 Rails 控制台中测试此逻辑。如果您在控制台本身中运行这些步骤,它会尝试显示最后一个返回值(我认为是通过调用 .inspect)并通过检查返回值来执行查询。因此,如果您将 a = Magazine.find(1).articles 放入控制台,您将看到一个立即执行的查询,如果代码在 Controller 操作的上下文中运行,则不会执行例如。如果您随后调用 a.limit(2),您将看到另一个查询等等。

关于ruby-on-rails - Rails 会自动优化查询吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27662235/

相关文章:

jquery - :has CSS pseudo class in Nokogiri

mysql - 针对旧数据库进行 Rails 测试

带下划线或句点的 SQL id 列

sql - 在一对多关系中按另一个表中的字段排序

python - 更快地向前填充和向后填充 groupby

python - TypeError : must be real number, 不是 GK_Operators

javascript - 我无法克服这个错误 "undefined local variable or method ` f'“有什么原因吗?

ruby-on-rails - rails : Facebox link if condition is satisfied

postgresql - 选择一段时间内的数据

CLI 模式下的 PHP APC