有多少个数据库索引太多?
我正在一个具有相当大的Oracle数据库的项目中工作(尽管我的问题同样适用于其他数据库)。我们有一个Web界面,允许用户搜索几乎任何可能的字段组合。
为了使这些搜索快速进行,我们将索引添加到我们认为用户通常会在其上进行搜索的字段和字段组合。但是,由于我们并不十分了解客户将如何使用该软件,因此很难确定要创建哪些索引。
空间不是问题;我们有一个4 TB的RAID驱动器,我们只使用其中的一小部分。但是,我担心索引过多会导致性能下降。由于每次添加,删除或者修改行时都需要更新这些索引,因此我认为在单个表上包含数十个索引是一个坏主意。
那么多少索引被认为太多呢? 10个? 25吗50吗还是我应该只介绍真正,非常普遍和显而易见的案例,而忽略其他所有内容?
解决方案
这取决于表上发生的操作。
如果有很多SELECT且更改很少,请对所有我们喜欢的内容进行索引....(可能)加快SELECT语句的速度。
如果表受到UPDATE,INSERT + DELETE的严重打击,那么使用大量索引的速度将非常慢,因为每次执行这些操作之一时都需要修改它们
话虽如此,我们可以清楚地向表添加很多毫无意义的索引,这些索引什么也做不了。将B-Tree索引添加到具有2个不同值的列中将毫无意义,因为它在查找数据方面不会增加任何内容。列中的值越独特,则从索引中受益越多。
最终,需要多少索引取决于驻留在数据库服务器之上的应用程序的行为。
通常,插入越多,索引就越痛苦。每次执行插入操作时,都必须更新包含该表的所有索引。
现在,如果应用程序具有不错的读取量,或者甚至更多,如果几乎全部读取,那么索引就成为必经之路,因为它将以很少的成本实现重大的性能改进。
如果我们主要阅读(很少更新),那么实际上没有理由不对需要索引的所有内容进行索引。如果我们经常更新,那么我们可能需要对拥有多少索引保持谨慎。没有确切的数字,但是我们会注意到事情开始放缓的时间。确保聚簇索引是最有效的基于数据的索引。
有几列?
我总是被告知要创建单列索引,而不是多列索引。因此,索引不超过列数,恕我直言。
我们可能会考虑的一件事是建立索引以定位标准搜索组合。如果通常搜索column1,并且经常将column2与之一起使用,并且有时将column3与column2和column1一起使用,则按顺序在column1,column2和column3上使用的索引可以用于这三种情况中的任何一种,尽管它是只需要维护一个索引。
真正的原因是,不要添加索引,除非我们知道(并且这通常意味着收集使用情况统计信息)它的使用频率远比其更新的频率高。
任何不符合该标准的索引将比在不使用索引的情况下浪费性能而付出更多的重建成本。
在关于爱因斯坦的简单描述中,可以根据需要添加任意多个索引,而无需添加更多索引。
但是,严重的是,每当将数据添加到表中时,添加的每个索引都需要维护。在主要是只读的表上,很多索引是一件好事。在高度动态的表上,越少越好。
我的建议是讲解常见和明显的情况,然后,当我们遇到需要从特定表中获取数据的速度更快的问题时,请评估并添加索引。
同样,每隔几个月重新评估索引方案是一个好主意,以查看是否有需要索引的新内容或者我们创建的索引没有被用于任何事物,因此应予以删除。
我认为没有静态答案,这种情况属于"性能调整"范畴。
可能是应用所做的所有操作都由主键查找,也可能是相反的查询是在无限制的字段组合上进行的,尤其是任何特定时间都可以使用。
除了索引之外,还对数据库进行了重新粒度化,以包括计算出的搜索字段,拆分表等,这实际上取决于负载形状和查询参数,查询需要"真正"恢复多少/什么数据。
如果整个数据库都以存储过程外观为前导,则转弯会变得容易一些,因为我们不必担心每个临时查询。或者,我们可能对将要命中数据库的查询有深刻的了解,并且可以将调优限制在这些查询上。
对于SQL Server,我发现数据库引擎优化顾问对我们设置"典型"工作负载很有用,它可以为添加/删除索引和统计信息提供建议。我确信其他数据库有类似的工具,无论是"官方"还是第三方。
这确实是一个比实际问题更多的理论问题。索引对性能的影响取决于所拥有的硬件,Oracle的版本,索引类型等。昨天,我听说Oracle宣布了一种由HP生产的专用存储,该存储在使用11g数据库的情况下应该能快10倍。
对于情况,可以有几种解决方案:
1.拥有大量索引(> 20)并每天(每晚)重建它们。如果表每天获得数千个更新/删除,这将特别有用。
2.对表进行分区(如果适用于数据模型)。
3.使用单独的表存储新的/更新的数据,并运行一个每晚将数据组合在一起的过程。这将需要更改应用程序逻辑。
4.如果数据支持,请切换到IOT(索引组织表)。
对于这种情况,当然可能会有更多解决方案。我对第一个建议是将数据库克隆到开发环境中,并对它进行一些压力测试。
我通常这样进行。
- 获取在典型一天中对数据运行的真实查询的日志。
- 添加索引,以便最重要的查询在其执行计划中命中索引。
- 尽量避免索引具有大量更新或者插入内容的字段
- 在几个索引之后,获取一个新的日志并重复。
与所有优化一样,当达到要求的性能时,我会停止(这显然暗示着0点将达到特定的性能要求)。
更新基础表时,索引会产生成本。索引用于加速查询时会带来好处。对于每个索引,我们需要在成本与收益之间取得平衡。没有索引的查询运行速度会降低多少?运行更快有多少好处?缺少索引时,我们或者用户能否忍受速度慢?
我们可以忍受完成更新所花费的额外时间吗?
我们需要比较成本和收益。这对情况特别重要。没有任何神奇的指标可以超过"太多"的阈值。
还有存储索引所需的空间成本,但是我们已经说过,这不是问题。考虑到磁盘空间已变得多么便宜,在大多数情况下也是如此。
在数据仓库中,拥有大量索引是很常见的。我使用的事实表有两百列,其中有190个已建立索引。
尽管这样做有开销,但必须从上下文中了解到,在数据仓库中,我们通常只插入一次行,但我们从不更新它,但是它可以参与数千个SELECT查询,这可能会受益于对任何列。
为了获得最大的灵活性,数据仓库通常使用单列位图索引,但在高基数列上除外,在高基数列上可以使用(压缩的)btree索引。
索引维护的开销通常与写入大量块的开销有关,并且随着新行的添加,该块拆分时添加的值位于该列的现有值范围的"中间"。可以通过分区并使新的数据负载与分区方案对齐,以及使用直接路径插入来缓解这种情况。
为了更直接地解决问题,我认为首先对显而易见的内容建立索引可能很好,但不要担心针对该表的查询是否会受益而添加更多索引。
其他所有人一直在为我们提供很好的建议。在我们前进的过程中,我还为我们提供了一些建议。在某些时候,我们必须决定最佳的索引编制策略。最后,最好的PLANNED索引策略仍然可以最终创建不会被使用的索引。一种可以让我们查找未使用的索引的策略是监视索引使用情况。我们可以按照以下步骤进行操作:
alter index my_index_name monitoring usage;
然后,可以通过查询v $ object_usage监视从那时起是否使用索引。有关此信息,可以在Oracle中找到?数据库管理员指南。
只需记住,如果我们有一种在更新表之前先删除索引然后重新创建它们的仓储策略,则必须设置索引以再次进行监视,并且该索引将丢失任何监视历史记录。
除了其他所有人提出的要点外,如果存在更多索引,则基于成本的优化器还会在为SQL语句创建计划时产生成本,因为要考虑的组合更多。我们可以通过正确使用绑定变量来减少这种情况,以使SQL语句保留在SQL缓存中。然后,Oracle可以进行软解析并重新使用上次发现的计划。
与往常一样,没有什么是简单的。如果涉及倾斜的列和直方图,那么这可能是个坏主意。
在我们的Web应用程序中,我们倾向于限制我们允许的搜索组合。否则,我们必须逐字测试每种组合的性能,以确保我们不会遇到某个人会发现某天的潜伏问题。我们还实施了资源限制,以防止在出现问题时在应用程序中的其他位置引起问题。
我对真实的项目和真实的MySql数据库进行了一些简单的测试。我已经在以下主题中回答了:为多个数据库列建立索引的成本是多少?
但是我认为如果在这里引用它会更好:
I made some simple tests using my real project and real MySql database. My results are: adding average index (1-3 columns in an index) to a table - makes inserts slower by 2.1%. So, if you add 20 indexes, your inserts will be slower by 40-50%. But your selects will be 10-100 times faster. So is it ok to add many indexes? - It depends :) I gave you my results - You decide!
Sql server为我们提供了一些不错的工具,可让我们查看实际使用的索引。
本文http://www.mssqltips.com/tip.asp?tip=1239提供了一些查询,使我们可以更好地了解索引的使用量,而不是索引的更新量。
它完全基于Where子句中使用的列。
并且作为经验法则,我们必须在外键列上具有索引以避免DEADLOCKS。
AWR报告应定期分析以了解索引的需求。