我们的项目运行一个非常大、非常复杂的数据库。所以大约一个月前,我们注意到包含空值的索引列所使用的空间变得太大了。作为对此的回应,我编写了一个脚本,该脚本将动态搜索包含超过 1% 的空值的所有单列索引,然后在值不为 NULL 的情况下删除并重新创建这些索引作为过滤索引。这将在整个数据库中删除并重新创建数百个索引,通常会释放整个数据库所用空间的近 15%。
现在我有两个问题:
A) 以这种方式使用过滤索引的缺点是什么?我会假设它只会提高性能,但是否存在任何性能风险?
B) 我们在删除和重新创建索引时收到错误(“无法删除索引 XYZ,因为它不存在或您没有权限”),即使事后检查时,一切都完全按预期进行。这怎么会发生?
谢谢你的帮助!
编辑:回应@Thomas Kejser
嗨,谢谢,但事实证明这是一场灾难。当时我们不明白几件事,例如:
- 在查询期间,SQLOS 在确定它不能使用 NULL 值连接表列之前制定索引计划。IE,你真的需要有一个 WHERE 子句过滤器来适应查询中使用的每个过滤索引的索引,否则根本不会使用索引。
- 删除和创建索引并在之后再次冗余地更新它们的统计信息可能仍然不足以产生更新的计划,我们假设它们会。在某些情况下,似乎只有足够高的工作负载才会迫使 SQL Server 重新评估计划。
- 执行计划器的功能有一些奇异之处,仅凭常识和逻辑很难确定。甚至有数以千计的代码隐藏生成的不同查询变体,看似无用的索引可以帮助最终用于关键查询的一些统计和查询计划。
最后,这些更改被恢复了。所以过滤索引是一个强大的工具,但您需要真正了解从这些列中提取的数据到底是什么。除了空间问题之外的普通索引很容易应用,过滤索引代表了非常定制的解决方案。它们当然不是常规索引的替代品,而是在需要它们的特殊情况下对它们的扩展。
非常有趣的方法。我对创造力的支持。
由于您回收了空间,我假设原始索引不再存在?过滤索引的缺点是:
实际上,这意味着您必须非常小心地使用过滤索引,因为它们通常会导致糟糕的查询计划。我不会说它们没用,但我认为它们是对传统索引的补充,而不是替代(正如您正在尝试做的那样)。
Thomas Kejser在上面很好地回答了这个话题。
我只是想加 2 美分。
我看到一些过滤索引仅在您将查询中的 where 子句与过滤索引中的 where 完全匹配时才使用(显示在执行计划中)。
您是否尝试过使用索引视图? 稀疏列?
我相信,就您只有内部关节而言,您可以创建一个包含过滤索引的 where 子句的索引视图,然后您可以改用该视图。
可能有不止一种观点。但与非聚集索引一样,太多会减慢您的写入速度。
根据我的经验,您在阅读方面会有很好的收获,但如果表涉及复制,您将不得不特别监视写入(插入和更新)。
但是,据我了解,您主要关心的是
the null values
因此我建议您在索引中使用 SPARSE 列。稀疏列特别适用于过滤索引
正如我宣传的稀疏列一样,如果我不告诉你它的局限性,我会感觉不舒服:
由于这个
考虑具有 600 个 bigint 类型的稀疏列的表的示例。
有关上面链接的更多详细信息,但是我更愿意在这里发布此警告:
SQL Server 数据库引擎使用以下过程来完成此更改:
1 - 以新的存储大小和格式向表中添加一个新列。
2 - 对于表中的每一行,将存储在旧列中的值更新并复制到新列中。
3 - 从表架构中删除旧列。
4 - 重建表(如果没有聚集索引)或重建聚集索引以回收旧列使用的空间。