所以我的群组模型有很多成员,有些成员是彼此的朋友,有些则不是。我想创建一个用户可以通过我的应用程序发出请求的控制器操作,它会返回如下所示的哈希:
{ group : { members: { friends: group_friends, others: group_others } } }
我通过ruby中的集合交叉完成了以下操作:
group_members = group.all_members
user_friends = current_user.all_friends
user_group_friends = group_members & user_friends
user_group_others = group_members - user_group_friends
我的问题是,由于这是红宝石 - 在性能方面,使用连接的数据库查询是否会更好?或者我应该保持原样....
我也很好奇这个查询会是什么样的......
仅供参考:这些是我正在与之合作的关系:
Group
has_many :members, class_name: "User"
has_many :inverse_members....
# all_members retrieves members who have added, been added
User
has_many :user_groups
has_many :groups, :through => :user_groups
has_many :friendships
has_many :friends, :through => friendships
has_many :inverse_friends....
....
# all_friends retrieves all friends who have added, been added
User_Groups
belongs_to :user
belongs_to :group
Friendship
belongs_to :user
belongs_to :friend
group_members = group.all_members # Instance method uses returns associated members
group_members_friends = group_members.where("? in friends OR ? in inverse_friends", current_user, current_user)
给出此错误
# --- Caused by: ---
# SQLite3::SQLException:
# no such table: friends
ActiveRecord::StatementInvalid:
SQLite3::SQLException: no such table: friends: SELECT "users".* FROM "users" INNER JOIN "user_groups" ON "users"."id" = "user_groups"."user_id" WHERE "user_groups"."group_id" = ? AND (1 in friends OR 1 in inverse_friends)
因为允许group.all_members发生的连接(User_Groups)不包含字段朋友(显然通过上述关联)...如何访问相关的每个成员(用户)并检查他们的朋友??
group_members = group.all_members # Instance method uses returns associated members
group_members_friends = group_members.where("id in ?", current_user.all_friends)
给出了这个错误:
# --- Caused by: ---
# SQLite3::SQLException:
# near "2": syntax error
ActiveRecord::StatementInvalid:
SQLite3::SQLException: near "2": syntax error: SELECT "users".* FROM "users" INNER JOIN "user_groups" ON "users"."id" = "user_groups"."user_id" WHERE "user_groups"."group_id" = ? AND (user.id in 2,3)
答案 0 :(得分:3)
在这种查询中,数据库引擎最有可能比Ruby快得多。连接操作由引擎直接提供,因此它们具有多年的本地语言优化功能。
即使编译了调用语言(例如Java或C ++),我认为依赖引擎实现的连接操作仍然会更快。根据经验,引擎及其工程师在大多数情况下都是聪明的(首先是因为它们 in )。
我与亚历山大·迪莫没有任何关系,但我推荐他的书Ruby Performance Optimization提供有关此类问题的提示,基准和其他内容。顺便提一下,他解决了这一点。
答案 1 :(得分:2)
在评估数据库的时候要知道的要点会更快:
现在,将此应用于您的情况:此时,您只收到了一些单独的查询,因此您对第3点的确定没问题。到目前为止您还没有提到性能问题,所以你可能很好:第5点,应该保持原样。
但是如果你想继续(可能是过早的)优化:
关于第4点 - 您是否将逻辑推迟到数据库?
好吧,如果您查看自ActiveRecord::Relation
使用的方法,他们实际上只是委托给records
。 (你可以通过例如group_members.all.method(:-).source_location
然后查看源代码来找到它。现在,通过运行:recrods
检查group_members.records.class.name
是什么,得到Array
- 也就是说,-
和&
方法正在对Ruby结果数组执行操作 - 所以,这意味着减法/加法逻辑正在Ruby中发生,并且不会被推迟到数据库。这意味着如果您处理大量结果,它可能会很慢。
就改变这一点而言,最初的预感可能是尝试在一个查询中获得所有结果 - 但这是一个坏主意,因为您仍然需要逐个使用Ruby过滤它们,实例化许多ruby对象,将它们放入各自的类别中。所以这里的逻辑仍然发生在ruby中。
如果您想优化性能,您要做的就是有4个数据库查询 - 每个类别一个 - 但每个查询都会返回该类别的整个结果集,以避免您执行{{1}或者类似于Ruby。
这只是伪代码,我不知道你的域名,但是像:
group_members & user_friends
...并且您为每个类别都这样做。