这是关于ActiveRecord查询方法的问题:
first
查找第一条记录(如果提供参数,则为前N条记录)。如果没有定义订单,它将按主键排序。take
给出一条记录(如果提供了参数,则为N条记录),没有任何隐含的顺序。订单将取决于数据库实施。如果提供订单,则会受到尊重。用例: 例如,基于唯一属性从数据库中检索记录。
User.where(email: 'f@example.com')
这里,
first
生成
SELECT "users".* FROM "users" WHERE "users"."email" = 'f@example.com' ORDER BY "users"."id"` ASC LIMIT 1
take
生成
SELECT "users".* FROM "users" WHERE "users"."email" = 'f@example.com' LIMIT 1
如上所述,first
增加了额外的排序条款。我想知道take
与first
之间是否存在性能差异。
take
比first
快,反之亦然?
答案 0 :(得分:34)
通常,“take”会更快,因为数据库不必识别符合条件的所有行,然后对它们进行排序并找到排序最低的行。 “take”允许数据库在找到单行后立即停止。
它的快速程度将根据以下情况而变化:
在不必查找多行的情况下节省了多少时间。这里最糟糕的情况是需要对大型表进行全扫描,但在扫描的早期就会发现一个匹配的行。 “take”将允许扫描停止。
需要对多少行进行排序才能找到ID最低的行。这里最糟糕的情况是表中的每一行都符合条件,并且需要包含在排序中。
还有一些其他因素需要考虑 - 例如,对于“第一个”查询,优化器可能能够通过扫描主键索引来访问表,并检查每一行以查看它是否与条件匹配。如果这种可能性非常高,那么如果查询优化器足够复杂,则可以避免完整的数据扫描和排序。
在许多情况下,只有很少的匹配记录和基于索引的访问权限才能找到它们,您会发现差异很小(在您的示例中“电子邮件”中有唯一索引)。但是,即便如此,我仍然会优先使用“take”。
编辑:我只是添加,虽然它有点偏离主题,但在您的示例中,您可以使用:
User.find_by(email: 'f@example.com')
生成的查询应该与take完全相同,但我认为语义更清晰。