我有一个(有点)复杂的查询,返回 60K 多条客户记录。我有两个左外连接,需要与查询一起使用来搜索关联记录:
customers = customers.
left_outer_joins(:phones, :emails).
select("customers.id, customers.name, ...")
if params[:sSearch].present?
params[:sSearch] = parse_phone_number(params[:sSearch])
customers = customers.where(
"customers.name like :search OR
..
phones.number like :search OR
emails.email like :search",
search: "%#{params[:sSearch]}%"
)
end
customers = customers.
group('customers.id').
order("#{sort_column} #{sort_direction}).
page(page).
per(per_page)
(注意:这在数据表 ajax 调用中使用,因此 sort_column、sort_direction、page 和 per_page 都是其参数。)
我的所有索引都已排好。
这是我面临的主要问题:如果我不使用 group('customers.id'),由于左外连接,它将返回重复的客户记录。但添加 group 子句似乎会使查询时间增加至少 2 倍。在查询末尾使用 .distinct 似乎比使用 group 还要慢一点。
是否有更好/更快的方法来不返回具有左外连接的重复项而不显着增加查询时间?目前这需要超过 1000 毫秒。
编辑:为了回答下面影子的评论 - 我正在加入多个电话/电子邮件,因为我需要搜索它们。我期望的是,如果客户记录与搜索匹配(假设在已连接的手机上),它只会返回一个客户 - 而不是两个。
最佳答案
如果您只想搜索地址/电话号码,但不想显示它们,请使用带有子查询的存在运算符而不是联接。
sql 中的代码如下所示:
select *
from customers c
where c.name like '%...%'
or exists (select 1 from emails e where e.email like '%...%' and e.customer_id=c.id) ...
但是,如果您确实想显示地址和电话号码,则必须使用联接。在这种情况下,您可能需要使用 MySQL 的内置 group_concat() 函数将各种地址和电话号码连接成一个值。
其他需要考虑的事情:
- 使用
union
代替一系列or
条件 - 尽可能尝试使用全文索引和搜索,而不是
like
,因为like '%...%'
过滤器无法使用索引来加速查询。
关于mysql - Rails/MySQL : Group/Distinct doubles query time using LEFT JOINS/slow performance,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43762469/