我是公司数据库团队的一员,目前面临查询优化和性能方面的困境。每当我的一些同事遇到查询速度慢时,他们的默认解决方案就是创建索引来加快查询速度。这导致一些表有超过 70 个索引!
就我个人而言,我倾向于以不同的方式处理这个问题。我经常发现自己修改现有索引(例如添加额外的包含列等)以加快查询速度,而不是每次都创建新索引。然而,并非所有团队成员都采用这种方法,导致我们数据库中的索引数量不断增加。
尽管做出了这些努力,我还是注意到,随着索引数量的增加,其他 DML 操作的速度有所减慢。这似乎是一个第二十二条军规:没有索引,查询会很慢,但是有了索引,其他一切都会变慢一点。
我正在寻求有关如何应对这种情况的建议。有多少索引通常被认为“太多”?是否有任何最佳实践或策略来平衡快速查询的需求与整体数据库性能?
任何见解或资源将不胜感激。
谢谢你!
我通常喜欢遵循 5x5 准则。每个表五个索引,每个索引不超过五个字段。但这是一个指导原则,而不是硬性限制。有时我会发现一个用例需要索引中的七个字段,有时一个表需要十个索引,等等。无论如何,问题的关键是,任何松散地围绕该指南的内容通常都可能是合理的。
一张表上有 70 多个索引,听起来不合理,可能按照大多数人的标准。如果您发现它影响了该表的写入速度,那么这可能是您系统的直接信号,表明您的表太多。考虑一下,表中是否有 70 列?...如果没有,则索引数量远多于部分覆盖您能想到的每个可能谓词所需的索引数量。
对我来说,听起来现有索引可能有很多重叠,应该重新评估它们。我毫不怀疑有些可以合并到一个索引中,而另一些甚至可能不再被使用那么多。检测哪些索引使用率较低的一个好工具是
sp_BlitzIndex
.更加了解索引设计,不创建冗余或未使用的索引会很有帮助。
查询调优而不是索引调优作为首要选择有时也会有所帮助。并不是所有的性能问题都只能通过索引来解决。有时有更有效的方法来重写查询。
还有其他用于具体化数据的工具,例如持久计算列和索引视图。
让应用程序以您需要的形式写入数据,以便最大限度地减少查询的复杂性。
重新架构表结构以提高效率。例如,也许一个宽表可以分为多个较小的表,特别是如果这些列之间的数据不需要在事务上彼此一致。那么单个表上的索引数量就可以减少。
如果您确实需要向表添加另一个索引,请考虑是否可以将其设为Filtered Index,以便它仅适用于数据的子集,从而更快地写入表。
如果人们想要更快地查询特别慢的查询,物化视图是一个很好的通用解决方案。他们只是在更新相关表时计算答案,这样当您需要结果时,它们就已经准备好了。
另一个具体的架构变化是分区表。它们很有用的一个场景示例是,假设您每天都会获得 1000 件事情的数据。你有一张桌子,比方说,
date, thing_id, attr1, attr2, attr3
。由于新数据每天都会出现,因此当您将数据插入表中时,它们会按天物理分块。现在假设当您查询数据时,您通常只想查询其中的一项。当您执行该查询时,即使索引良好,即使存储位于 SSD* 上,它也必须从驱动器中获取物理结果,然后将其丢弃,这意味着它必须读取更多内容。分区表使得每个分区键都有(可能是错误的命名法)子表。这样,当您进行插入时,它会将每个新数据放入适当的分区中,以便类似数据在物理上靠近其他类似数据。当您按该分区进行查询过滤时,它可以比未分区更快地获取该数据。*尽管 SSD 没有可以移动来读取数据的物理磁头,但它们仍然具有要读取的最小块大小。