big*_*ief 9 sql-server index-tuning unique-constraint
在我的数据库中,我有一个带有两个索引的表。出于数据完整性原因,a、b 列上有一个唯一索引 #1。我有另一个索引 #2,其中包含 c、a、b 列,用于性能原因。我注意到这个索引#2 也是唯一的。
在我看来,索引#2 的唯一性似乎是多余的,因为索引#2 中不可能有重复值,而索引#1 中也不可能有重复值。我很想更改索引 #2,使其不再唯一,因为我想象数据库引擎可能会对索引 #2 中的 c、a、b 执行第二次检查,以确保每次插入行时这些列的唯一性,从而导致即使永远不会有重复的值,也会影响性能。它是否正确?
有没有办法删除 a、b 上的索引 #1 并保留 c、a、b 上的索引 #2,但仍然只对 a、b 列施加唯一约束,而不维护两个单独的索引?这将允许我只有一个索引包含所有三列,但仍然对 a、b 强制执行数据完整性约束。为了提高性能,我不需要在 a、b 上建立索引,因为我所有的选择查询都在 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
Run Code Online (Sandbox Code Playgroud)
这些查询通常包括选择不在任何索引中的许多其他列。
我们通常不会运行这样的查询:
Select [stuff] from table where a=2 and b=3
Run Code Online (Sandbox Code Playgroud)
在我看来,索引#2 的唯一性似乎是多余的,因为索引#2 中不可能有重复值,而索引#1 中也不可能有重复值。
是的,声明索引 #2唯一是多余的。索引 #1 需要存在来支持外键,因此它被删除的可能性很小。
我很想更改索引 #2,使其不再唯一,因为我想象数据库引擎可能会对索引 #2 中的 c、a、b 执行第二次检查,以确保每次插入行时这些列的唯一性,从而导致即使永远不会有重复的值,也会影响性能。
这是错误的关注点。SQL Server总是需要找到插入点。如果它找到所提供的键的现有行并且索引被标记为唯一,则会引发错误。否则,新行将插入到正确的位置。
不必要地将索引标记为唯一会产生更重要的后果。任何更改键列之一的更新都需要进行特殊处理,以避免更新处理期间出现暂时性键冲突。在 SQL Server 中,这意味着额外的Split、Sort和Collapse运算符以及对受影响索引的广泛(每个索引)维护。
这比您担心的问题要贵得多。
有没有办法删除 a、b 上的索引 #1 并保留 c、a、b 上的索引 #2,但仍然只对 a、b 列施加唯一约束,而不维护两个单独的索引?
不。
为了提高性能,我不需要在 a、b 上建立索引,因为我所有的选择查询都在 where 子句中包含 c 列。
示例查询表明,c 列上的等式谓词本身就有足够的选择性,优化器会选择非聚集索引查找加查找计划。优化器对于选择这种类型的计划非常谨慎,这意味着 c 列确实是非常有选择性的(或者估计很差)。
由于无论如何您都会检索索引之外的列,因此您很可能会发现仅在列 c 上使用非聚集非唯一索引就足够了。
如果足够的查询受益于更精确的索引寻求来证明额外的空间和维护的合理性,则将 a 和/或 b 添加到索引键将很有用。只有您拥有足够的信息才能做出判断。
归档时间: |
|
查看次数: |
1608 次 |
最近记录: |