有多少数据库索引太多了?

时间:2008-09-26 18:50:14

标签: database oracle database-design

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

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

空间不是问题;我们有一个4 TB的RAID驱动器,我们只使用了一小部分。但是,我担心索引太多会导致性能损失。因为每次添加,删除或修改行时都需要更新这些索引,我想在单个表上有几十个索引是个坏主意。

那么有多少索引被认为太多了? 10? 25? 50?或者我应该覆盖真正的,非常常见和明显的案例而忽略其他一切?

17 个答案:

答案 0 :(得分:85)

这取决于桌面上发生的操作。

如果有很多SELECT和很少的更改,请索引所有你喜欢的....这些(可能)加速SELECT语句。

如果表受到UPDATE,INSERTs + DELETE的严重影响......由于每次执行其中一个操作时都需要修改这些索引,因此这些索引会非常缓慢

话虽如此,你可以清楚地向一个不会做任何事情的表中添加许多无意义的索引。将B-Tree索引添加到具有2个不同值的列将是没有意义的,因为它不会在查找数据方面添加任何内容。列中的值越独特,它就越能从索引中受益。

答案 1 :(得分:43)

我通常会这样做。

  1. 获取在典型日期对数据运行的真实查询的日志。
  2. 添加索引,以便最重要的查询在执行计划中点击索引。
  3. 尽量避免索引具有大量更新或插入的字段
  4. 在几个索引之后,获取一个新日志并重复。
  5. 与所有优化一样,我在达到要求的性能时停止(这显然意味着第0点将获得特定的性能要求)。

答案 2 :(得分:26)

其他人一直在给你很好的建议。当你前进时,我有一个额外的建议。在某些时候,您必须决定您的最佳索引策略。最后,最好的PLANNED索引策略仍然可以最终创建最终不会被使用的索引。允许您查找未使用的索引的一种策略是监视索引使用情况。您这样做如下: -

alter index my_index_name monitoring usage;

然后,您可以通过查询v $ object_usage来监视从该点开始是否使用索引。有关这方面的信息可以在Oracle® Database Administrator's Guide

中找到

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

答案 3 :(得分:14)

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

虽然存在开销,但必须在上下文中理解,在数据仓库中我们通常只插入一行,我们从不更新它,但它可以参与数千个SELECT查询,这些查询可能会从索引中受益在任何一栏上。

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

索引维护的开销主要与写入大量块的开销和块拆分相关联,因为新行添加的值为该列的现有值范围的“中间”。这可以通过分区并使新数据加载与分区方案对齐,并使用直接路径插入来缓解。

为了更直接地解决您的问题,我认为最初可能会对明显的索引进行索引,但如果针对该表的查询会受益,请不要害怕添加更多索引。

答案 4 :(得分:11)

Einstein关于简单性的解释中,根据需要添加尽可能多的索引,而不是更多。

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

我的建议是涵盖常见和明显的案例,然后,当您遇到需要更快速地从特定表中获取数据的问题时,请评估并添加索引。

此外,每隔几个月重新评估一次索引方案是一个好主意,只是为了查看是否有任何需要建立索引的新内容或您创建的任何未用于任何内容的索引应该是摆脱了。

答案 5 :(得分:6)

我对我的真实项目和真正的MySql数据库做了一些简单的测试。我已在本主题中回答:What is the cost of indexing multiple db columns?

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

  

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

     

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

     

添加多个索引可以吗? - 它   取决于:)我给你我的结果 - 你   决定!

答案 6 :(得分:6)

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

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

在我们的网络应用程序中,我们倾向于限制我们允许的搜索组合。否则你将不得不测试每个组合的性能,以确保你没有潜伏的问题,有人会找到一天。我们还实施了资源限制来阻止这会导致应用程序中的其他地方出现问题。

答案 7 :(得分:3)

最终需要多少索引取决于运行在数据库服务器上的应用程序的行为。

一般来说,插入越多,索引就会越痛苦。每次执行插入操作时,都必须更新包含该表的所有索引。

现在,如果您的应用程序具有相当大的读取量,或者如果几乎所有读取数据都更多,那么索引是可行的方式,因为只需很少的成本就可以实现重大的性能提升。

答案 8 :(得分:3)

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

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

答案 9 :(得分:3)

在我看来,没有静态的答案,这种情况属于“性能调整”。

可能是您的应用所做的一切都是通过主键查找的,或者它可能是相反的,因为查询是通过不受限制的字段组合完成的,特别是任何一个都可以在任何给定时间使用。

除了索引之外,还在重新编写数据库以包括计算的搜索字段,拆分表等 - 它实际上取决于您的负载形状和查询参数,查询需要重新检索的数据/数据。 / p>

如果您的整个数据库都是由存储过程外观转向变得更容易,因为您不必对每个特殊查询都有所了解。或者您可能对将会影响数据库的查询类型有深入的了解,并且可能会限制调优。

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

答案 10 :(得分:2)

索引在更新基础表时会产生成本。索引在用于扩展查询时提供了一个好处。对于每个指数,您需要平衡成本与收益。如果没有索引,查询运行速度会慢多少?运行得更快有多少好处?当您的索引丢失时,您或您的用户可以忍受速度慢吗?

您能否容忍完成更新所需的额外时间?

您需要比较成本和收益。这特别适合你的情况。没有超过“太多”阈值的神奇数量的索引。

还有存储索引所需空间的成本,但您已经说过在您的情况下这不是问题。考虑到磁盘空间的成本,在大多数情况下也是如此。

答案 11 :(得分:2)

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

答案 12 :(得分:2)

如果您主要阅读(并且很少更新),那么实际上没有理由不索引您需要索引的所有内容。如果您经常更新,那么您可能需要对您拥有的索引数量保持谨慎。没有硬数字,但你会注意到事情开始变慢的时候。确保您的聚簇索引是基于数据最有意义的索引。

答案 13 :(得分:1)

真正归结为,除非您知道(这通常意味着收集使用情况统计信息),否则不要添加索引,它将比使用更新时更频繁地使用。

任何不符合该标准的索引都会花费更多的时间来重建,而不是在使用它的奇怪情况下没有它的性能损失。

答案 14 :(得分:1)

有多少列? 我总是被告知要制作单列索引,而不是多列索引。因此没有比列数量更多的索引,恕我直言。

答案 15 :(得分:1)

Sql server为您提供了一些很好的工具,可以让您查看实际使用的索引。 本文http://www.mssqltips.com/tip.asp?tip=1239为您提供了一些查询,可让您更深入地了解索引的使用量,而不是更新量。

答案 16 :(得分:0)

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