Ruby on rails Ruby';s.where vs.detect
我正在寻找一种更快、使用更少服务器处理的方法。在我的应用程序中,我可以同时使用Ruby on rails Ruby';s.where vs.detect,ruby-on-rails,ruby,activerecord,Ruby On Rails,Ruby,Activerecord,我正在寻找一种更快、使用更少服务器处理的方法。在我的应用程序中,我可以同时使用.where和.detect: 其中: User.where(id: 1) # User Load (0.5ms) User.all.detect{ |u| u.id == 1 } # User Load (0.7ms). Sometimes increases more than .where 检测: User.where(id: 1) # User Load (0.5ms) User.all.detect{
.where
和.detect
:
其中:
User.where(id: 1)
# User Load (0.5ms)
User.all.detect{ |u| u.id == 1 }
# User Load (0.7ms). Sometimes increases more than .where
检测:
User.where(id: 1)
# User Load (0.5ms)
User.all.detect{ |u| u.id == 1 }
# User Load (0.7ms). Sometimes increases more than .where
我知道.detect
,但如果我有数千名用户,它与。where
相比如何
为清晰起见进行了编辑
本例中使用了。其中
,因为我可能无法单独查询id
。如果我有一个名为“name”的表列怎么办?NB在这种特殊情况下,应该使用ActiveRecord\find
,请参考@spickermann的答案
用户。其中
在数据库级别执行,返回一条记录
User.all.detect
将把所有记录返回给应用程序,然后在ruby级别进行迭代
也就是说,必须使用where
。前者可以抵抗大量记录,可能有数十亿条记录,并且执行时间/内存消耗几乎相同(O(1)
),后者甚至可能在数十亿条记录上失败。在本例中
User.find(1) # or
User.find_by(id: 1)
将是最快的解决方案。因为这两个查询都告诉数据库只返回一条具有匹配的id
的记录。一旦数据库找到一个匹配的记录,它就不再进一步查找,而是立即返回该记录
鉴于
User.where(id: 1)
将返回与条件匹配的对象数组。这意味着:在找到匹配的记录后,数据库将继续查找其他与查询匹配的记录,因此始终扫描整个数据库表。在这种情况下,由于id
很可能是一个具有唯一值的列,因此它将返回一个只有一个实例的数组
相反
User.all.detect { |u| u.id == 1 }
这将从数据库中加载所有用户。这将导致将数千个用户加载到内存中,构建ActiveRecord实例,迭代该数组,然后丢弃所有与条件不匹配的记录。与仅从数据库加载匹配记录相比,这将非常缓慢
数据库管理系统经过优化,可以运行选择查询,您可以通过设计有用的模式和添加适当的索引来提高它们的运行能力。从数据库加载的每条记录都需要转换为ActiveRecord的一个实例,并且会消耗内存——这两个操作都不是免费的。因此,经验法则应该是:尽可能直接在数据库中而不是在Ruby中运行查询 这里有一个通用指南:
User.where(id: 1)
# User Load (0.5ms)
User.all.detect{ |u| u.id == 1 }
# User Load (0.7ms). Sometimes increases more than .where
在查找唯一记录时,请使用.find(id)
。搜索非ID字段时,只要只有一条记录具有该特定值,就可以使用.find\u by\u email(email)
或.find\u by\u name(name)
或类似方法(这些finder方法是自动生成的)
如果您的查询对于.find\u by query来说太复杂,或者您需要使用排序,但仍然确定只需要返回一条记录,请使用.where(…).limit(1)
检索多个记录时使用。其中(…)
只有在无法避免时才使用
。检测。.detect的典型用例是在非ActiveRecord枚举上,或者当您有一组记录但无法在SQL中写入匹配条件时(例如,如果它涉及复杂函数)。由于.detect
是最慢的,请确保在调用.detect
之前,您已使用SQL尽可能缩小查询范围。.any?
和其他也一样。仅仅因为它们可用于ActiveRecord对象并不意味着它们是一个好主意;) 我假设从技术上讲,User.where(id:1)返回一个ActiveRecord集合代理?但是请注意find是正确的方法。@DavidAldridge:You's rightwhere
返回一个ActiveRecord关系(而不是数组)。在这个例子中,这并没有造成很大的区别,但在其他例子中,更精确可能很重要。那么,如果不仅仅是id
Im之后的问题呢?这就是为什么我在示例中使用.where
。@Sylar:查找
版本仅在使用主键时有效。当您只对一条(第一个匹配项)记录感兴趣时,应使用find_by
(find_by
是的捷径,其中(…).first
)<代码>其中
总是比all更快。检测多条记录的
。在定期查询非id
列上的表时,不要忘记添加索引。是的,find_by(email:…)
是数据库中电子邮件唯一时最快的解决方案。请确保在数据库列中添加uniq索引,不要只依赖Rails唯一性验证。这可能是零、一或多。Find是正确的ActiveRecord方法。在回答的开头,您有粗体的“NB”。这是什么意思?嗨,谢谢你的支持。这个问题是三年前的事了。您确定当时实施了find\u by
?