【问题标题】:Covering Index with ORDER BY使用 ORDER BY 覆盖索引
【发布时间】:2016-01-03 23:00:41
【问题描述】:

如果您有复合聚集索引,请说:(ClientId, Date, OrderId, ProductId)。 (所有字段都不为空)

给定查询:

SELECT * FROM products WHERE ClientId = 33 AND OrderId = 4 AND ProductId = 2 ORDER BY Date

此查询是否会通过 ORDER BY Date 充分利用覆盖索引,还是要求 Date 字段位于 WHERE 子句中?

我添加了主要数据库引擎的标签,以防每个引擎之间存在差异。

【问题讨论】:

  • 覆盖索引意味着查询中的所有列(包括Select 子句中的列)都在索引中。因此,Date 列也需要在索引中。顺便说一句:如果一个人看到这个查询和索引定义,他们不会知道它是否是一个覆盖查询。如果您使用 Select ClientId, OrderId, ... 而不是 Select * ... 会更清楚——这被广泛认为是生产代码的最佳实践。

标签: mysql sql sql-server database oracle


【解决方案1】:

将索引中的列重新排序为 ClientId、OrderId、ProductId、Date

然后将使用索引。

不,order by 不会帮助使用索引。 但是可以通过使用索引来帮助排序,

如果可以接受,您可以将订单更改为 ORDER BY ClientId, OrderId, ProductId, Date 那么它会使用相同的索引

或者,如果您没有更改索引中列的顺序,那么您可以将 order by 更改为 ORDER BY ClientId、Date 并且将使用索引

【讨论】:

    【解决方案2】:

    为了增加讨论,我实际上是在搜索堆栈 10 分钟后找到了答案(由于涉及的通用术语很难找到)。似乎是这个答案:Proper field orders for covering index - MySQL

    表示对于 MySQL SELECT WHERE GROUP BY HAVING ORDER BY 所有都是有效引用。

    我想知道 MSSQL 和 Oracle 是否也是如此

    【讨论】:

      【解决方案3】:

      这真的取决于很多事情,比如

      • 表中有多少行?
      • 从索引叶子获取值需要多少时间?
      • 你从中得到的 * 里面是什么

        等等

      这就是他们发明“解释计划”的原因

      想知道就用它

      【讨论】:

      • 我了解查询优化器可能会根据许多因素做它想做的事情,这个问题通常是为了更好地理解这个概念。此外,在我有问题的表上尝试这个也不可行,因为它有 2 亿条记录,并且测试索引比从 SO 获得更好的理解需要更多的时间。
      【解决方案4】:

      对于 MySQL,无法使用您的索引。 MySQL 的索引左->右应用:

      (ClientId, Date, OrderId, ProductId)
      

      由于您的查询仅涉及 ClientIDProductID,因此无法使用索引 - 您还必须在查询中使用 include DateOrderID。请注意,查询中字段的特定顺序是无关紧要的——重要的是它们是否被使用:

      因此,如果您的查询 where 有:

      clientid                     -> usable
      clientid, date               -> usable
      date, clientid               -> usable, order of usage irrelevant
      clientid, orderid            -> not usable, missing date
      clientid, orderid, productid -> also not usable, missing date
      clientid, productid          -> not usable, missing orderid, missing date
      date                         -> not usable missing clientid
      

      请注意,这仅适用于 mysql。其他一些数据库系统没有这个限制。

      【讨论】:

      • 我将OrderId 包含在内毫无价值,因此只有Date 存在问题,在这种情况下,它在ORDER BY 而不是WHERE
      • 在那种情况下,我不确定它是如何工作的。 whereorder 是查询的两个不同阶段,因此如果在另一个中未使用该字段,则在其中使用一个字段可能无济于事。无论如何,您可以通过explaining 查询来查看mysql 的执行计划。如果索引可以使用,它会显示出来
      • 你可以在日期序列中使用Date is not null吗?或 Date = Date 或任何不需要太多逻辑的东西
      • Date 不能为 NULL,任何其他字段也不能。
      猜你喜欢
      • 2013-09-20
      • 2011-09-29
      • 2012-03-27
      • 1970-01-01
      • 2018-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多