【问题标题】:Is an index on A, B redundant if there is an index on A, B, C?如果 A、B、C 上有索引,那么 A、B 上的索引是否多余?
【发布时间】:2012-11-27 07:08:45
【问题描述】:

拥有多年的 DBA 经验,我相信我知道问题的答案,但我认为检查我的基础永远不会有坏处。

使用 SQL Server,假设我有一个表,该表在列 A 和列 B 上具有索引,在列 A、B 和 C 上具有第二个索引,是否安全删除第一个索引,因为第二个索引基本上会满足将从第一个索引中受益的查询?

【问题讨论】:

  • 请参阅Group indexing in Informix 了解有关此主题的更多详细信息。
  • 有了免责声明,这个问题只是关于非聚集索引,对吗?否则,未来的读者,放弃聚集索引 A 以支持非聚集索引 B 会让你大吃一惊
  • @billinkc - 是的,仅限非聚集索引。聚集索引会影响数据的物理排序方式,非聚集索引必须使用该顺序,因此删除或更改聚集索引将对依赖它的任何其他索引产生深远影响。

标签: sql sql-server indexing


【解决方案1】:

第一个索引涵盖在 A、A,B 上查找的查询,第二个索引可用于涵盖在 A、A,B 或 A,B,C 上查找的查询,这显然是第一种情况。

如果C 非常宽,但是A,B 上的索引可能仍然有用,因为它可以以更少的读取满足某些查询。

例如如果C 是char(800) 列,则以下查询可能会因提供更窄的索引而显着受益。

SELECT a,b
FROM YourTable
ORDER BY a,b

【讨论】:

  • 我就是这么理解的:)
【解决方案2】:

是的,这是一种常见的优化。任何可以从 A、B 上的索引中受益的查询也可以从 A、B、C 上的索引中受益。

在 MySQL 社区中,甚至还有一个工具可以在整个架构中搜索冗余索引:http://www.percona.com/doc/percona-toolkit/pt-duplicate-key-checker.html

可能的例外情况是,如果 A、B 上的索引更紧凑且使用更频繁,并且您想控制哪个索引保持加载到内存中。

【讨论】:

  • A, B 将是更小的受益范围扫描。
  • @usr:关键是拥有 both 索引肯定比只有A,B,C 索引更大。
【解决方案3】:

这取决于,但答案通常是“是的,您可以将索引放在 (A,B) 上”。

反例(您不会删除 (A,B) 上的索引)是 (A,B) 上的索引是强制执行约束的唯一索引;那么您不想在 (A,B) 上删除索引。 (A,B,C) 上的索引也可以是唯一的,但唯一性是多余的,因为 (A,B) 组合是唯一的,因为另一个索引。

但是在没有这种异常情况的情况下(例如,如果 (A,B) 和 (A,B,C) 都允许重复条目),那么 (A,B) 索引在逻辑上是多余的。但是,如果列 C 是“宽”列(可能是 CHAR(100) 列),而 A 和 B 很小(比如 INTEGER),则 (A,B) 索引比 (A,B,C) 更有效) 索引,因为您可以获得 (A,B) 索引的每页读取的更多信息。因此,即使 (A,B) 是多余的,它也可能值得保留。您还需要考虑表格的波动性;如果表很少更改,则额外的索引无关紧要;如果表变化很大,额外的索引会减慢对表的修改。这是否重要很难猜测。您可能需要进行性能测量。

【讨论】:

  • 确实,+1 用于添加唯一性位。我知道有例外,但在这种情况下,我正在寻找一个通用的答复。
【解决方案4】:

我的大部分想法都是Jonathan 在之前的answer 中写的。独特性、更快的工作,以及我认为他错过的另一件事。

如果第一个索引是A desc, B asc 和第二个A asc, B asc, C asc,那么删除第一个索引并不是真正可行的方法,因为第二个索引不是第一个索引的超集,并且您的查询不能如果按照第一个索引中的顺序进行排序,则可以从第二个索引中受益。

在某些情况下,例如当您使用第一个索引时,您可以使用order by A desc, B asc(当然)和A asc, B desc,但您也可以进行使用该索引任何部分的查询,例如Order by A desc。

但是像order by A asc, B asc 这样的查询不会被第一个索引“覆盖”。

所以我想加起来,你通常可以删除第一个索引,但这取决于你的表配置和查询(当然还有索引)。

【讨论】:

  • 我将赏金奖励给你,因为你提出了一个解释清楚的新角度:-)
【解决方案5】:

我通常会在包含历史数据的表中找到这个“几乎”相似的索引。如果column C 是日期或整数列,请小心。它最有可能用于满足WHERE tblA.C = MAX(tblB.C) 中的 MAX 函数,它完全跳过表并使用仅索引访问路径。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-02
    • 2012-12-18
    • 1970-01-01
    • 2012-04-06
    • 1970-01-01
    • 2017-04-06
    • 2011-03-09
    • 1970-01-01
    相关资源
    最近更新 更多