在我的数据库中,我有一个包含两个索引的表。由于数据完整性的原因,在列a,b上有一个唯一的索引#1。我有另一个索引#2,列c,a,b,用于性能原因。我注意到这个索引#2也是唯一的。
在我看来,索引#2的唯一性似乎是多余的,因为在索引#2中如果没有重复的值,就不可能有重复的值。我很想更改索引#2,所以它不再是唯一的,因为我认为数据库引擎可能会对索引2中的c、a、b执行第二次检查,以确保每次插入行时这些列的唯一性,从而导致性能下降,尽管永远不会有重复的值。这是正确的吗?
有没有办法删除a,b上的索引#1,并将索引#2保留在c、a、b上,但仍然在不维护两个单独索引的情况下对仅仅列a、b施加唯一的约束?这将使我只能有一个包含所有三列的索引,但仍然在a,b上强制执行数据完整性约束。我不需要a,b上的索引来提高性能,因为我的所有select查询都在where子句中包含了列c。这是唯一约束的用例,而不是索引吗?我认为数据库引擎基本上处理这两个构造相同(参见下面的文章:什么时候应该使用唯一约束而不是唯一索引?)。
请记住,索引不是冗余的,但是索引的“唯一性”是冗余的。似乎让索引#2变得不独特是不明智的。但这是否会带来任何实际的性能收益?数据库是否检查两个索引的唯一性,即使索引#1中的列完全包含在索引#2中?
一些回答询问用于从此表中选择数据的示例查询。以下是最常见的例子:
Select [some other columns] from table where c=1 and a=2
Select [some other columns] from table where c=1
Select [some other columns] from table where c=1 and a=2 and b=3这些查询通常包括选择许多其他列,而不是在任何索引中。
我们通常从不运行的是这样的查询:
Select [stuff] from table where a=2 and b=3发布于 2022-10-04 08:27:58
在我看来,索引#2的唯一性似乎是多余的,因为在索引#2中如果没有索引#1中的重复值,就不可能有重复的值。
是的,声明索引2唯一是多余的。索引1需要存在以支持外键,因此它被删除的可能性很小。
我很想更改索引#2,因此它不再是唯一的,因为我设想数据库引擎可能在每次插入一行时对索引#2中的c、a、b执行第二次检查,以确保这些列的唯一性,从而导致性能下降,即使永远不会有重复的值。
这是不应该关注的事情。Server总是需要定位插入点。如果找到提供的键(S)的现有行,并且索引标记为唯一,则会引发错误。否则,将在正确的位置插入新行。
对一个指数进行不必要的标记会有一个更重要的后果。任何更改键列之一的更新都需要特殊处理,以避免在更新处理期间发生短暂的密钥冲突。在Server中,这意味着要对受影响的索引进行额外的拆分、排序和折叠操作,以及对每个索引进行广泛的维护。

这比你关心的要贵得多。
有没有办法删除a,b上的索引#1,并将索引#2保留在c、a、b上,但仍然在不维护两个单独索引的情况下对仅仅列a、b施加唯一的约束?
不是的。
我不需要a,b上的索引来提高性能,因为我所有的select查询都在where子句中包含了列c。
示例查询表明,仅在第c列上的相等谓词就具有足够的选择性,以至于优化器选择了一个非聚集索引查找加上查找计划。优化器对于选择这种类型的计划是谨慎的,这意味着列c实际上是非常有选择性的(或者估计值很差)。
由于您正在检索索引之外的列,您很可能会发现仅在列c上有一个非聚集的非唯一索引就足够了。
如果有足够多的查询从更精确的索引中受益,则向索引键添加a和/或b将非常有用,以证明额外的空间和维护是合理的。只有你有足够的信息才能做出这个判断。
发布于 2022-10-04 00:48:43
Server将索引与基表数据保持同步。当将一行插入到表中时,也会将其添加到所有相关索引中。
索引是有序的。因此,必须将新行添加到每个索引中的正确位置。在找到了添加新行的正确位置之后,查看该位置中是否存在一个现有值是非常简单的。检查唯一性的开销很小。
是的,在插入期间,表上有多个索引的开销。但这是因为有多个索引必须与表保持一致。它与索引是否唯一无关。
在读取数据时,使用重叠索引有很多好处。格兰特的回答涵盖了这一点。开销和收益之间的平衡将取决于您的工作负载。
如果索引是唯一的,那么最好将其声明为唯一索引。查询优化器在构造查询计划时使用该信息。由于这两个索引都声明为唯一,优化器更有可能提出更好的平均计划,而不是这样。尽可能多地向优化器提供有关数据的信息,以帮助其完成工作。
没有办法将索引列的子集声明为唯一和多余的(另一个索引的一部分)。
发布于 2022-10-03 13:06:16
因此,这是两个不同的索引,具有不同的关键结构。是的,A,B上的#1是在#2中复制的,但是C列的增加意味着它也必须是唯一的,与A&B组合在一起,这并不是索引1行为的重复,它是分开的和不同的。
如果设置为#1是A,B和#2是A,B,C,那么#1将是一个冗余索引,可能不需要。然而,即使在这里,也必须谨慎行事。因为,在这个场景中,#1比#2小。所以,1的扫描可能比2的扫描要快,这取决于。在这种情况下,#1用于一些查询,即使它是#2的副本。
另外,当不同的列是索引中的第一列时,它们会在统计信息中产生不同的直方图。这些不同的直方图可能对不同的查询有用。因此,A、B列的唯一索引可能支持不同的查询,而不是B、A列的唯一索引,尽管从逻辑的角度来看,这些索引是相同的。
测试查询以了解如何使用索引是很重要的。随着时间的推移,监测性能也很重要。然后,当您找到一个合法的重复索引时,您可以判断删除它是否对性能是中性的,是否有助于性能,还是会损害性能。因为只要看一下索引及其结构,就不会告诉你它是如何在系统中使用的。
编辑:忘了包括这个。当然,维护也有开销,甚至可能会阻塞&资源争用,而索引太多。这就是为什么消除重复索引非常重要的原因。我不是说你不应该消除重复。只是您需要真正清楚地知道什么构成了副本(在本例中您没有),以及该副本是否存在于其他目的。
https://dba.stackexchange.com/questions/317762
复制相似问题