use*_*950 13 mysql activerecord ruby-on-rails database-performance ruby-on-rails-4
我使用ActiveRecord和MySQL进行以下设置:
用户通过成员身份拥有多个组通过成员身份,
组拥有许多用户
schema.rb中还描述了group_id和user_id的索引:
add_index "memberships", ["group_id", "user_id"], name: "uugj_index", using: :btree
Run Code Online (Sandbox Code Playgroud)
User.where(id: Membership.uniq.pluck(:user_id))`
Run Code Online (Sandbox Code Playgroud)
(3.8ms)SELECT DISTINCT
memberships
.user_id
FROMmemberships
User Load(11.0ms)SELECTusers
.*FROMusers
WHEREusers
.id
IN(1,2 ......)
User.where(id: Membership.uniq.select(:user_id))
Run Code Online (Sandbox Code Playgroud)
用户加载(15.2ms)SELECT
users
.*FROMusers
WHEREusers
.id
IN(SELECT DISTINCTmemberships
.user_id
FROMmemberships
)
User.uniq.joins(:memberships)
Run Code Online (Sandbox Code Playgroud)
用户负载(135.1ms)SELECT DISTINCT
users
.*FROMusers
INNER JOINmemberships
ONmemberships
.user_id
=users
.id
这样做的最佳方法是什么?为什么带连接的查询要慢得多?
第一个查询是错误的,因为它将所有用户id吸收到Ruby数组中,然后将它们发送回数据库.如果你有很多用户,这是一个巨大的阵列和巨大的带宽,加上2次往返数据库而不是一次.此外,数据库无法有效处理这个庞大的数组.
第二种和第三种方法都是有效的数据库驱动的解决方案(一种是子查询,一种是连接),但您需要具有适当的索引.你需要在memberships
桌子上有一个索引user_id
.
add_index :memberships, :user_id
您已经拥有的索引仅在您想要查找属于特定组的所有用户时才有用.
更新:
如果您在有大量列和数据users
表中,DISTINCT users.*
在第三查询将是相当缓慢的,因为MySQL有一个大量的数据,以确保其唯一性比较.
要明确:这不是内在的缓慢JOIN
,而是缓慢的DISTINCT
.例如:这是一种避免使用DISTINCT
和仍然使用的方法JOIN
:
SELECT users.* FROM users
INNER JOIN (SELECT DISTINCT memberships.user_id FROM memberships) AS user_ids
ON user_ids.user_id = users.id;
Run Code Online (Sandbox Code Playgroud)
鉴于所有这些,在这种情况下,我相信第二个查询将是最适合您的方法.如果添加上述索引,第二个查询应该比原始结果中报告的更快.如果您在添加索引后还没有这样做,请重试第二种方法.
虽然第一个查询本身有一些缓慢的问题,但是从你的评论中可以看出它仍然比第三个查询更快(至少对于你的特定数据集).这些方法的权衡取决于您的特定数据集,关于您拥有多少用户以及您拥有多少成员资格.一般来说,我认为第一种方法仍然是最差的,即使它最终更快.
另请注意,我推荐的索引特别针对您在问题中列出的三个查询而设计.如果您对这些表有其他类型的查询,则可以通过其答案中提到的@tata为其他索引或可能的多列索引提供更好的服务.
归档时间: |
|
查看次数: |
1044 次 |
最近记录: |