多少数据库索引太多?


109

我正在一个具有相当大的Oracle数据库的项目中工作(尽管我的问题同样适用于其他数据库)。我们有一个Web界面,允许用户搜索几乎任何可能的字段组合。

为了使这些搜索快速进行,我们将索引添加到我们认为用户通常会在其上进行搜索的字段和字段组合。但是,由于我们并不真正了解客户将如何使用该软件,因此很难确定要创建哪些索引。

空间不是问题;我们有一个4 TB的RAID驱动器,我们只使用其中的一小部分。但是,我担心索引过多会导致性能下降。因为每次添加,删除或修改行时都需要更新这些索引,所以我认为在一个表上包含数十个索引是一个坏主意。

那么多少索引被认为太多呢?10个?25吗 50吗 还是我应该只介绍真正,非常普遍和显而易见的案例,而忽略其他所有内容?

Answers:


87

这取决于表上发生的操作。

如果有很多SELECT且更改很少,请对所有您喜欢的内容进行索引....(可能)加快SELECT语句的速度。

如果该表受到UPDATE,INSERT + DELETE的严重打击,那么使用大量索引的速度将非常慢,因为每次执行这些操作之一时都需要修改它们

话虽如此,您可以清楚地向表添加很多毫无意义的索引,这些索引什么也没做。将B-Tree索引添加到具有2个不同值的列中将毫无意义,因为它在查找数据方面不会增加任何内容。列中的值越独特,则从索引中受益越多。


1
需要说明的是,在2个值上的索引在特定情况下可能不是没有意义的,当一个值很少发生并且您要查找它时。因此,这与值的唯一性无关,而与索引的选择性有关。
charlie_pl

44

我通常这样进行。

  1. 获取在典型一天中对数据运行的实际查询的日志。
  2. 添加索引,以便最重要的查询在其执行计划中命中索引。
  3. 尽量避免索引具有大量更新或插入内容的字段
  4. 经过几个索引后,获取新日志并重复。

与所有所有优化一样,当达到请求的性能时,我停止了(这显然暗示着0点将达到特定的性能要求)。


26

其他人一直在给您很好的建议。在您前进的过程中,我还有其他建议。在某些时候,您必须决定最佳的索引编制策略。最后,最好的PLANNED索引策略仍然可以最终创建不会被使用的索引。一种可以让您查找未使用的索引的策略是监视索引使用情况。您可以按照以下步骤进行:

alter index my_index_name monitoring usage;

然后,可以通过查询v $ object_usage监视从那时起是否使用索引。有关此信息,请参见《Oracle®数据库管理员指南》

只需记住,如果您有一种在更新表之前先删除索引然后重新创建它们的仓储策略,则必须将索引设置为再次进行监视,并且将丢失该索引的所有监视历史记录。


14

在数据仓库中,拥有大量索引是很常见的。我使用的事实表有两百列,其中有190个已建立索引。

尽管这样做有开销,但必须从上下文中了解到,在数据仓库中,我们通常只插入一次行,但我们从不对其进行更新,但是它可以参与数千个SELECT查询,这可能会受益于对任何列。

为了获得最大的灵活性,数据仓库通常使用单列位图索引,但在高基数列上则可以使用(压缩的)btree索引。

索引维护的开销通常与写入大量块的开销有关,并且随着新行的添加,该块拆分时添加的值位于该列的现有值范围的“中间”。可以通过分区并使新数据负载与分区方案对齐,以及使用直接路径插入来缓解这种情况。

为了更直接地解决您的问题,我认为首先对显而易见的内容建立索引可能很好,但是不要害怕针对该表的查询是否会增加更多的索引。


有那么多事实吗?我猜你会说尺寸。那是一个非常奇怪的用例。但是,您作为DBA感到震惊,所以我要说,我显然缺少了一些东西。
Stephanie Page

@Stephanie,我们有几乎相同的情况.. David提到了那些是位图索引。我们还使用BITMAP JOIN索引。是的,基于事实。Oracle可以对位图索引执行非常高效的AND操作。例如,您可能具有5个低基数属性的WHERE子句,每个属性都有一个位图索引。如果查看执行计划,它将有一个位图AND操作(基本上是一个有效的位图和操作),然后在执行计划下,您将看到位图转换为rowid。真的很快。
塔加

12

在关于爱因斯坦的简单描述中,可以根据需要添加任意多个索引,而不必添加更多索引。

但是,严重的是,每当将数据添加到表时,添加的每个索引都需要维护。在主要是只读的表上,很多索引是一件好事。在高度动态的表上,越少越好。

我的建议是讲解常见和显而易见的情况,然后,当您遇到需要从特定表中获取数据的速度更快的问题时,请评估并添加索引。

另外,最好每隔几个月重新评估索引编制方案,以查看是否有需要索引的新内容或已创建的索引未用于任何用途,因此应将其删除。


1
我同意重新评估。良好的管理绝不是“一劳永逸”的任务。软件变更。需求变更。用法更改。一天推出的一项看似微不足道的新功能可能会很快成为您最大的瓶颈,而昨天的基础性代码可能变得枯燥无味,只会浪费资源。我也同意采用迭代方法。如果一次执行太多操作,您将不知道什么有效。
durette

6

除了其他所有人提出的要点外,如果存在更多索引,则基于成本的优化器还会在为SQL语句创建计划时产生成本,因为要考虑的组合更多。您可以通过正确使用绑定变量来减少这种情况,以使SQL语句保留在SQL缓存中。然后,Oracle可以进行软解析并重新使用上次发现的计划。

与往常一样,没有什么是简单的。如果涉及倾斜的列和直方图,那么这可能是个坏主意。

在我们的Web应用程序中,我们倾向于限制我们允许的搜索组合。否则,您必须逐字测试每种组合的性能,以确保您不会遇到某个人会发现某天的潜伏问题。我们还实施了资源限制,以防止在出现问题时在应用程序中的其他地方引起问题。


我投了赞成票,但是...我会说,额外的解析时间既有趣又学术,它永远不会影响我对正确数量索引的选择。同意?
斯蒂芬妮·佩奇

@StephaniePage我还没有做实验来证明任何事情。但是,我确实看到了一个项目,该项目天真的在每列上创建了一个单列索引。如果某些表有80列,我想它可能会开始产生影响。Oracle似乎考虑了每个索引的访问成本。但是,是的,我同意,还有比这更重要的事情要考虑。
WW。

嗯...我认为,Oracle将在硬解析中花费最大的时间...考虑一个具有多个表(例如7或8)的SQL,仅连接顺序选择就可以产生数百种可能访问路径。
Stephanie Page

6

我对真实的项目和真实的MySql数据库进行了一些简单的测试。我已经在以下主题中回答了:为多个数据库列建立索引的成本是多少?

但是我认为如果在这里引用它会更好:

我使用真实的项目和真实的MySql数据库进行了一些简单的测试。

我的结果是:将平均索引(索引中的1-3列)添加到表中-使插入速度降低2.1%。因此,如果添加20个索引,则插入速度将降低40-50%。但是您的选择将快10-100倍。

那么可以添加许多索引吗?-取决于:)我给了我我的结果-您决定!


没有所有细节,这不应被视为预言。特别是因为您不能将一项操作的性能收益/损失乘以另一项。基础保持不变:添加更多索引,由于重新创建索引,插入最终将变慢。
苏联边疆'19

3

最终,您需要多少个索引取决于驻留在数据库服务器之上的应用程序的行为。

通常,插入越多,索引就越痛苦。每次插入时,包含该表的所有索引都必须更新。

现在,如果您的应用程序具有不错的读取量,或者甚至几乎所有读取量都更多,那么索引就是您的理想之选,因为将以很少的成本提高性能。


3

我认为没有静态答案,这种情况属于“性能调整”范畴。

可能是您的应用程序执行的所有操作都由主键查找,也可能是相反的,查询是在无限制的字段组合上完成的,尤其是在给定的任何时间都可以使用。

除了索引之外,还对数据库进行了重新粒度化,以包括计算出的搜索字段,拆分表等-它实际上取决于您的负载形状和查询参数,一个查询需要“真正”恢复多少/什么数据。

如果您的整个数据库都以存储过程外观为前导,则转弯会变得容易一些,因为您不必担心每个临时查询。或者,您可能对将要命中数据库的查询类型有深刻的了解,并且可以将调整限制在这些查询上。

对于SQL Server,我发现数据库引擎优化顾问非常有用-您设置了“典型”工作负载,它可以为添加/删除索引和统计信息提供建议。我确信其他数据库有类似的工具,无论是“官方”还是第三方。


3

这确实是一个比实际问题更多的理论问题。索引对性能的影响取决于所拥有的硬件,Oracle的版本,索引类型等。昨天,我听说Oracle宣布了一种由HP生产的专用存储,该存储在11g数据库中的运行速度应提高10倍。对于您的情况,可以有几种解决方案:1.拥有大量索引(> 20)并每天(每晚)重建它们。如果表每天有成千上万的更新/删除,这将特别有用。2.对表进行分区(如果适用于您的数据模型)。3.使用单独的表存储新的/更新的数据,并运行一个每晚将数据组合在一起的过程。这将需要更改您的应用程序逻辑。4.如果您的数据支持,请切换到IOT(索引组织表)。

对于这种情况,当然可能会有更多解决方案。我对您的第一个建议是将数据库克隆到开发环境中,并对它进行一些压力测试。


我不明白重建索引将有什么帮助,或者物联网将有帮助。
David Aldridge

IOT-如果可以重新设计应用程序,以便使用新的用户定义的数据类型,则IOT将节省索引表的开销。在这里可能并非如此。这真的取决于。重建索引-如果索引很多,并且新数据未建立索引。
Moshe

IOT仍然是索引结构,与常规索引相比,块拆分的开销更大。“重建索引-如果有很多索引,而新数据没有被索引” ...您正在谈论的是哪个RDBMS,它不会为新条目自动维护索引?
David Aldridge

大卫-你当然是对的。我将其与SQL Server仅按需求索引全文搜索的功能混合在一起。希望Oracle拥有它,因为在这种情况下它可能很有用。我建议坚持其他两个建议。
Moshe

2

如果您主要阅读(很少更新),那么实际上没有理由不对您需要索引的所有内容进行索引。如果您经常更新,那么您可能需要谨慎使用多少索引。没有确切的数字,但是您会注意到事情开始放缓的时间。确保您的聚集索引是最有效的基于数据的索引。


2

您可能会考虑的一件事是建立索引以定位标准搜索组合。如果通常搜索column1,并且经常将column2与之一起使用,并且有时将column3与column2和column1一起使用,那么按顺序对column1,column2和column3的索引可以用于这三种情况中的任何一种,尽管只需要维护一个索引。


2

更新基础表时,索引会产生成本。索引用于加速查询时会带来好处。对于每个索引,您需要权衡成本与收益。没有索引的查询运行速度降低多少?运行更快有多少好处?缺少索引时,您或您的用户能否忍受速度慢?

您可以忍受完成更新所花费的额外时间吗?

您需要比较成本和收益。这对您的情况特别重要。没有神奇的数量可以超过“太多”的阈值。

存储索引也需要空间,但是您已经说过,这不是问题。考虑到磁盘空间已变得多么便宜,在大多数情况下也是如此。


1

有几列?我总是被告知要创建单列索引,而不是多列索引。因此,索引不超过列数,恕我直言。


1

真正的原因是,不要添加索引,除非您知道(并且这通常意味着收集使用情况统计信息)它的使用频率远比更新的频率高。

任何不符合该标准的索引将比在不习惯使用索引的情况下要付出的性能损失要多得多。



0

它完全基于Where子句中使用的列。并且作为经验法则,我们必须在外键列上具有索引以避免DEADLOCKS。AWR报告应定期分析以了解索引的需求。


2
外键列上的索引以避免死锁?您是否有参考资料解释这种情况的原因和方式?
杰伊·沙利文
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.