【问题标题】:Is there such thing as Index "hopping" in MySQL?MySQL中是否存在诸如索引“跳跃”之类的东西?
【发布时间】:2020-10-12 17:28:00
【问题描述】:

假设我们在 (A, B) 上有一个索引,在 (B, C) 上有一个索引。当做这样的查询时:

SELECT * FROM table WHERE A = const AND B = const ORDER BY C DESC

查询优化器会先在 (A,B) 索引中搜索以过滤 WHERE 类的行,然后再使用 (B, C) 索引快速排序吗?

或者查询仅限于一个索引?没有 B-tree 跳跃?

【问题讨论】:

  • MySQL 很少使用两个索引。但仅适用于 AND 或 OR,不适用于 ORDER BY。
  • 两个半相关的东西要研究:“MRR”和“loose scan”。
  • 有趣的话题,谢谢你提到@RickJames

标签: mysql sql database indexing database-design


【解决方案1】:

不,MySQL 没有按照您的描述进行操作。

它将执行以下操作之一:

  • (A, B) 索引中读取,它将使用索引仅检查匹配的行,但需要额外的工作来执行文件排序以按C 对行进行排序。

  • (B, C) 索引读取,它将以正确的顺序读取行,因此跳过文件排序。但它会检查大量具有不匹配的 A 值的额外行,并且必须逐一评估这些行并丢弃那些不匹配的行。

您可以通过将(A, B) 索引替换为(A, B, C) 上的索引来优化两者,这将只检查匹配的行,并以所需的顺序读取它们,因此不需要文件排序。

InnoDB 总是以某种索引顺序读取行。二级索引或聚集索引。


你的问题:

一般来说,MySQL 只读取每个表引用的一个索引。例如,这允许使用自连接进行查询,因此同一个表有多个表引用。每个表引用可能使用不同的索引读取。

例如,经理与其员工的自我加入:

SELECT ...
FROM employees AS m
JOIN employees AS e ON e.manager_id = m.id
WHERE m.hire_date = '2020-01-01'

在此示例中,它可能使用hire_date 上的索引来选择经理,并使用manager_id 上的索引来选择经理的下属。这是两个不同的表引用,因此分开阅读。

MySQL 还有一个称为index merge optimization 的功能,它可能会读取表的两个子集,可能使用不同的索引,然后使用联合或交集合并结果。但我发现这并不像你想象的那么频繁。

关于 ORDER BY DESC,https://dev.mysql.com/doc/refman/8.0/en/descending-indexes.html 说:

以前,可以以相反的顺序扫描索引,但会降低性能。

在 MySQL 8.0 中,他们实现了对声明要按降序构建的索引的支持,以支持 ORDER BY DESC 查询。但是索引是针对这些查询量身定制的,并且对 ASC 查询使用相同的索引会受到影响。因此,您可能需要在同一张表的相同列上创建两个索引。阅读我链接到的文档页面了解更多详细信息。

【讨论】:

  • ORDER BY 子句是 DESC 有什么区别吗?此外,查询是否总是仅限于使用一个索引?
  • @LudovicoVerniani - 我很确定即使在这种情况下,DESC 也会受到尊重和高效。 (没有文件排序)。这在 MySQL 8.0 之前应该是正确的,它在索引定义中尊重 DESC。
  • 比尔,你听说过“以前……逆序”是否不仅仅是小罚?
  • @RickJames,Jeremy Cole 关于 InnoDB 内部的演讲。但是点了,他没有量化,我自己也没有测量。
  • 我编造了一个粗略的测试——它表明 DESC 有轻微但微不足道的减速。
【解决方案2】:

当然,您可以测试您的数据。但根据我的经验,索引将首先匹配where 子句。因此,它将匹配 (A, B) 索引。

然后它将执行排序的排序。

【讨论】:

    【解决方案3】:

    你问:

    查询优化器会首先在 (A,B) 索引中搜索以过滤 WHERE 类的行吗?

    是的,如果谓词与UNIQUE 约束匹配,MySQL 可能会使用第一个索引来检索行,使用带有开始和停止谓词的“索引范围扫描”或“索引搜索”。

    ...然后随后使用(B,C)索引快速排序?

    不。第二个索引不包括使用第一个索引过滤的行。引擎将检索所有行(不再使用流水线),对它们进行排序,然后将它们提供给您。如果有很多行,则此阶段将占用大量资源且速度较慢。希望过滤谓词只产生几行。

    【讨论】:

      猜你喜欢
      • 2011-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-28
      • 2010-09-14
      • 2013-08-09
      • 1970-01-01
      相关资源
      最近更新 更多