【问题标题】:MySQL: Composite Index on Where + Order ByMySQL:关于 Where + Order By 的综合索引
【发布时间】:2022-01-17 19:18:53
【问题描述】:

我有一个简单的查询,它使用由另一列排序的 where 子句。

select * 
from `Domains` 
where `status` != 'error_name_not_resolved' 
order by `analyzed_at` asc limit 10;

我有三个索引:

  • 一个用于status 列。
  • 一个用于analyzed_at 列。
  • statusanalyzed_at 列的一个复合索引。

不过,查询真的很慢,即使 5 分钟后我也没有得到答案(该表包含 1400 万个文档)。

奇怪的是,同样的查询降序的速度确实很快(响应以毫秒为单位)。

select * 
from `Domains` 
where `status` != 'error_name_not_resolved' 
order by `analyzed_at` desc limit 10;

我还可以看到复合索引不是与EXPLAIN 一起使用的索引。

我错过了什么吗? ????

【问题讨论】:

  • (analyzed_at, status) 的综合索引可能会有所帮助……但概率不高。如果不是没有索引可能会有所帮助。
  • 什么是大约。具有status = 'error_name_not_resolved'的行的百分比?
  • @Akina,大约 1% 到 2%,还有什么是无索引? (在 Google 上找不到答案)
  • @Akina 我认为可能有帮助的索引实际上是您提到的索引,但是交换了列。
  • 为了帮助您解决query-optimization 的问题,我们需要更多信息。具体来说,一个表定义和 EXPLAIN 输出。请read this,然后edit您的问题。

标签: mysql sql performance query-optimization database-performance


【解决方案1】:

status 和analyzed_at 列的一个复合索引。

如果我正确阅读了图像,则说明您没有 那个 索引。相反,INDEX 中的列以相反的顺序排列。

通常,“范围”测试应该在 INDEX 中的最后一个,而不是第一个。

但是,status != 也是一个“范围”,因此您无法优化查询。

也许……

由于具有 status 值的行数很少,因此这个组合可能就足够了:

SELECT *
    FROM (
        SELECT *
            FROM `Domains` 
            ORDER BY `analyzed_at` ASC
            LIMIT 20  -- note: bigger than desired
         ) AS x
    WHERE `status` != 'error_name_not_resolved' 
    ORDER BY `analyzed_at` ASC
    LIMIT 10  -- note: the desired number

解释:

  • “派生”表查找最旧的 20 行(使用索引,如下所示)。
  • 外部查询只看到 20 行,并过滤掉任何状态错误的行。警告:希望仍然至少有 10 行
  • 最后它对 20 行进行排序并限制为您想要的 10 行。 (不能假设保持内部查询的顺序。)
  • 外部查询将使用任何索引。但是,只有 20 行,性能不是问题。

此公式需要INDEX(analyzed_at) 或以analyzed_at 开头的任何索引。 (显然你有。)

20 比 14,000,000 好多了!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-29
    • 2011-09-29
    • 2012-03-27
    • 2021-09-01
    相关资源
    最近更新 更多