【问题标题】:Order by query is taking too much time按查询排序需要太多时间
【发布时间】:2013-10-18 15:54:24
【问题描述】:

我有 80k 多个客户和 4 个组。现在我想在 mysql 中找到 2 组用户进行查询。我的查询如下:

select c.customers_firstname as recipient_firstname, 
       c.customers_lastname as  recipient_lastname,
       c.customers_id as recipient_id, 
       c.customers_email_address as recipient_email_address 
from customers c
where customers_group_id = '1' OR customers_group_id = '3'

当我在 phpmyadmin 中运行此查询时,我得到了结果:显示第 0 - 29 行(总共 59,815 行,查询耗时 0.0034 秒)

但是当我在这个查询中添加ORDER BY recipient_firstname ASC 的顺序时,结果时间是:显示第 0 - 29 行(总共 59,815 行,查询耗时 0.2607 秒)

按查询排序需要太多时间才能得到结果。

我想减少查询下单的时间。

如果有其他方法可以在更短的时间内获得相同的结果,请提供帮助。

【问题讨论】:

  • recipient_firstname 字段上创建索引。另外,请尝试:where customers_group_id IN (1, 3)
  • 好吧,当遇到针对 mysql 的特定查询的性能问题时,一如既往:尝试 mysql 中出色的“解释”功能!它告诉你问题出在哪里!

标签: php mysql sql


【解决方案1】:

您需要在recipient_firstname 字段上建立索引(所以真的是customers.customers_firstname)。索引允许对结果集进行有序的线性时间迭代。

如果没有索引,则必须对结果集进行聚合然后排序。这种排序将是n log n。对于大型集合来说,这显然很慢,如果它无法放入内存(60k 记录可能不取决于配置),它将执行基于文件的非常慢的排序。

tl;dr 你需要一个索引。 recipient_firstname 上的索引将使查询在性能上非常接近非 ORDER BY 版本。


顺便说一句,如果customers_group_id 是一个整数字段,请使用整数文字,而不是字符串。它可能不会产生影响,但它具有误导性,实际上在某些情况下它很重要。


根据情况,可能还值得在组 ID 上放置一个索引。对于小集合,可以在构建集合时过滤结果,但对于大结果集,最终需要进行相当大的磁盘全表扫描。

【讨论】:

  • 你不认为索引也应该包含 group_id 吗?因为这是 WHERE 的一部分,忽略它可能会使这个查询在以后有更多数据时变慢,即使现在不是
  • @Hanky웃Panky 只要他的无序查询运行得很快,我假设他已经在 group_id 上有一个索引。
  • 我认为这可能是因为它的整数值和 80k 记录对于整数比较来说毫无意义。可能值得一提以补充您的答案
【解决方案2】:

您必须在customers_firstname 字段上建立索引:这将加快ORDER BY但也会减慢WHERE(现在可能已编制索引)。

所以索引必须按这个顺序是customers_group_id, customers_firstname

CREATE INDEX my_query_ndx 
    ON customers ( customers_group_id, customers_firstname );

理论上,您可以将索引放大为一个覆盖索引,并在两个关键字段之后包含您在SELECT 中需要的所有其他字段。但是,维护这种索引很昂贵。你必须平衡优点和缺点。如果表非常“宽”,则对组 id、名字、姓氏、id 和电子邮件进行索引可能是有利的。

小的(或不那么小的)查询改进

where customers_group_id = '1' OR customers_group_id = '3'

为了清楚起见,可以将其重写为

WHERE customers_group_id IN ('1','3')

但是现在,customer_group_id 要么是整数字段,要么不是。如果是,那么最好这样对待:

WHERE customers_group_id IN (1, 3)

在某些情况下,您可以提前计划您的 ID,例如第 3 组实际上是第 2 组,即您可能感兴趣的组是连续的。这样,您可以将查询重写为variable < valuevariable > valuevariable BETWEEN,其速度是OR 的两倍。使用大型 OR 集,您可以轻松获得 4 倍的加速。

如果它不是一个整数字段,那么一定要努力使它成为一个。整数性能(和索引大小)将受益匪浅(但请注意,对于字符串,'3' 大于 '12',就像 'C' 大于 'AB';因此,类型转换不一定没有边效果)。

【讨论】:

    【解决方案3】:

    尝试创建索引(customers_group_id, customers_firstname) - 这应该可以。

    【讨论】:

    • 当我们知道这只是一个错字并且不会改变答案的设计时,为什么不继续编辑它
    【解决方案4】:

    您需要在应用 order by 子句的列上create index

    CREATE INDEX index_name ON customers (customers_firstname);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-15
      • 1970-01-01
      • 2017-07-06
      相关资源
      最近更新 更多