Rails/MySQL:使用 LEFT JOINS 的 Group/Distinct 使查询时间加倍/性能降低

Posted

技术标签:

【中文标题】Rails/MySQL:使用 LEFT JOINS 的 Group/Distinct 使查询时间加倍/性能降低【英文标题】:Rails/MySQL: Group/Distinct doubles query time using LEFT JOINS / slow performance 【发布时间】:2017-05-03 14:10:26 【问题描述】:

我有一个(有点)复杂的查询,它返回 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)

(注意:这是在 datatables ajax 调用中使用的,因此 sort_column、sort_direction、page 和 per_page 都是该参数。)

我的所有索引都排成一行。

这是我面临的主要问题:如果我不使用组('customers.id'),由于左外连接,它将返回重复的客户记录。但是添加 group 子句似乎会使查询时间增加至少 2 倍。在查询末尾使用 .distinct 似乎比使用 group 还要慢一些。

有没有更好/更快的方法在不显着增加查询时间的情况下不返回带有左外连接的重复项?现在这需要超过 1000 毫秒。

编辑:回答影子下面的评论 - 我要加入多个电话/电子邮件,因为我需要搜索它们。我期望的是,如果客户记录与搜索匹配(比如说在连接的电话上),它只会返回一个客户,而不是两个。

【问题讨论】:

最大的问题是您的查询违反了 sql 标准,从业务逻辑的角度来看也没有太大意义。如果您为客户存储了多个地址/电话号码,您的查询应该返回哪一个?他们中的任何一个?全部? 就像 Shadow 说你的 SQL 是错误的...阅读 psce.com/blog/2012/05/15/…... 你不应该使用 GROUP BY 删除重复的 DISTINCT 是为此而构建的。 对 Ruby 不太熟悉,但我的猜测是在末尾添加 .distinct 并删除 group() 语句。 也就是说,LIKE 的性能不太可能与 FULLTEXT INDEX 和 MATCH 一样好 如果您只想搜索地址/电话号码,但不想显示它们,请使用带有子查询的exists 运算符而不是连接。但是,如果您确实想显示地址和电话号码,则必须使用联接。在这种情况下,您可能希望使用 mysql 的内置 group_concat() 函数将各种地址和电话号码连接成一个值。我不知道如何通过 Rails 表达这些。我只能用sql给出答案。 【参考方案1】:

如果您只想搜索地址/电话号码,但不想显示它们,请使用带有子查询的存在运算符而不是连接。

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 '%...%' 过滤器无法使用索引来加快查询速度。

【讨论】:

关于如何使用全文索引和搜索而不是点赞,您可以提供任何指导吗?

以上是关于Rails/MySQL:使用 LEFT JOINS 的 Group/Distinct 使查询时间加倍/性能降低的主要内容,如果未能解决你的问题,请参考以下文章

单个 Prisma 查询中的 LEFT JOINS 和聚合

两个 SQL LEFT JOINS 产生不正确的结果

sql JOINs - JOIN,INNER JOIN,LEFT JOIN,RIGHT JOIN,CROSS JOIN

用于在不同表上具有多个 LEFT OUTER JOINS 的 SQL 的 LINQ

SQL Server JOINS:SQL Server 中是不是默认关联“JOIN”语句“LEFT OUTER”? [复制]

Caml 多表关联查询