多少数据库索引太多了?
Posted
技术标签:
【中文标题】多少数据库索引太多了?【英文标题】:How many database indexes is too many? 【发布时间】:2010-09-13 13:31:31 【问题描述】:我正在开发一个使用相当大的 Oracle 数据库的项目(尽管我的问题同样适用于其他数据库)。我们有一个网络界面,允许用户搜索几乎任何可能的字段组合。
为了加快这些搜索的速度,我们正在为我们认为用户通常会搜索的字段和字段组合添加索引。但是,由于我们并不真正知道我们的客户将如何使用该软件,因此很难确定要创建哪些索引。
空间不是问题;我们有一个 4 TB 的 RAID 驱动器,我们只使用了其中的一小部分。但是,我担心索引过多可能会导致性能损失。因为每次添加、删除或修改行时都需要更新这些索引,所以我认为在一个表上拥有数十个索引是个坏主意。
那么有多少索引被认为是太多了? 10? 25? 50?还是我应该只涵盖真正、非常常见和明显的案例而忽略其他所有内容?
【问题讨论】:
【参考方案1】:这取决于表上发生的操作。
如果有很多 SELECT 并且更改很少,索引所有你喜欢的......这些将(可能)加快 SELECT 语句的速度。
如果表受到 UPDATEs、INSERTs + DELETEs 的严重影响......这些会非常慢,因为有很多索引,因为每次发生这些操作之一时都需要修改它们
话虽如此,您可以清楚地向一个不会执行任何操作的表添加许多无意义的索引。将 B-Tree 索引添加到具有 2 个不同值的列将毫无意义,因为它不会在查找数据方面添加任何内容。列中的值越独特,它就越能从索引中受益。
【讨论】:
澄清一下,在特定情况下,当一个值很少发生并且您想查找它时,2 个值的索引可能不是毫无意义的。因此,重要的不是值的唯一性,而是索引的选择性。【参考方案2】:我通常是这样进行的。
-
获取在典型日期对数据运行的真实查询的日志。
添加索引,以便最重要的查询在其执行计划中命中索引。
尽量避免索引具有大量更新或插入的字段
在几个索引之后,获取一个新日志并重复。
与所有优化一样,当达到请求的性能时我会停止(这显然意味着点 0. 将获得特定的性能要求)。
【讨论】:
【参考方案3】:其他人一直在给你很好的建议。在你前进的过程中,我有一个额外的建议给你。在某些时候,您必须决定您的最佳索引策略。但最终,最好的 PLANNED 索引策略最终仍然会创建最终不会被使用的索引。让您找到未使用的索引的一种策略是监视索引使用情况。你可以这样做:-
alter index my_index_name monitoring usage;
然后,您可以通过查询 v$object_usage 来监控该索引是否被使用。这方面的信息可以在Oracle® Database Administrator's Guide找到。
请记住,如果您有一个在更新表之前删除索引然后重新创建它们的仓储策略,您将不得不重新设置索引以进行监控,并且您将丢失该索引的所有监控历史记录。
【讨论】:
【参考方案4】:在数据仓库中,拥有大量索引是很常见的。我使用过具有 200 列和其中 190 列的事实表。
虽然这有开销,但必须在上下文中理解,在数据仓库中,我们通常只插入一次行,我们从不更新它,但它可以参与数以千计的 SELECT 查询,这可能会受益于索引在任何列上。
为了获得最大的灵活性,数据仓库通常使用单列位图索引,但高基数列除外,其中可以使用(压缩)btree 索引。
索引维护的开销主要与写入大量块和块拆分的费用有关,因为新行添加了该列现有值范围“中间”的值。这可以通过分区和使新数据负载与分区方案保持一致以及使用直接路径插入来缓解。
为了更直接地解决您的问题,我认为一开始索引显而易见的问题可能很好,但不要害怕添加更多索引来确定针对表的查询是否会受益。
【讨论】:
事实有这么多?我猜你会说维度。这是一个相当奇怪的用例。但是,你作为一个 DBA 摇滚,所以我要说,我显然错过了一些东西。 @Stephanie,我们有非常相似的场景......大卫提到那些是位图索引。我们还使用 BITMAP JOIN 索引。是的,根据事实。 Oracle 可以对位图索引执行非常高效的 AND 操作。例如,您可以拥有具有 5 个低基数属性的 WHERE 子句,每个属性都有一个位图索引。如果您查看执行计划,它将有一个位图 AND 操作(基本上是一个有效的位图和操作),然后在执行计划中您会看到位图转换为 rowid。真的很快。【参考方案5】:在Einstein 中关于简单性的解释中,添加尽可能多的索引,而不是更多。
但是,当数据添加到表中时,您添加的每个索引都需要维护。在主要是只读的表上,大量索引是一件好事。在高度动态的表上,越少越好。
我的建议是涵盖常见和明显的情况,然后当您遇到需要更快地从特定表中获取数据的问题时,评估并添加索引。
另外,每隔几个月重新评估一次索引方案是个好主意,只是看看是否有任何新的需要索引的内容,或者您创建的任何未用于任何用途的索引,应该是摆脱了。
【讨论】:
我同意重新评估。良好的管理绝不是“一劳永逸”的任务。软件变更。需求变化。用法变化。某天引入的一项看似微不足道的新功能可能很快成为您最大的瓶颈,而昨天的基础代码可能会变成休眠的、不必要的脂肪,只会消耗资源。我也同意迭代方法。如果你一次做太多,你将不知道什么是有效的。【参考方案6】:除了其他人提出的观点之外,如果有更多索引,则基于成本的优化器在为 SQL 语句创建计划时会产生成本,因为要考虑的组合更多。您可以通过正确使用绑定变量来减少这种情况,以便 SQL 语句保留在 SQL 缓存中。然后,Oracle 可以进行软解析并重新使用上次找到的计划。
一如既往,没有什么是简单的。如果涉及倾斜的列和直方图,那么这可能是个坏主意。
在我们的网络应用程序中,我们倾向于限制我们允许的搜索组合。否则,您将不得不对每一种组合的性能进行逐字测试,以确保您没有任何人有一天会发现的潜在问题。我们还实施了资源限制,以防止出现问题时在应用程序的其他地方引起问题。
【讨论】:
我投了赞成票,但是...我会说额外的解析时间虽然有趣且学术性强,但它永远不会影响我选择正确数量的索引。同意吗? @StephaniePage 我没有做过实验来证明什么。然而,我确实看到一个项目天真地在每一列上创建了一个单列索引。如果某些表有 80 列,我想它可能会开始产生影响。 Oracle 似乎考虑了每个索引的访问成本。但是,是的,我同意,还有比这更重要的事情要考虑。 嗯...我相信 Oracle 将在硬解析中花费的最大时间...考虑一个包含多个表(例如 7 或 8 个)的 SQL 连接仅订单选择就可能产生数百种可能的访问路径。【参考方案7】:我对我的真实项目和真实的 mysql 数据库做了一些简单的测试。这个话题我已经回答过了:What is the cost of indexing multiple db columns?
不过我觉得这里引用会更好:
我用我的真实做了一些简单的测试 项目和真实的MySql数据库。
我的结果是:添加平均指数 (索引中的 1-3 列)到表 - 使插入速度降低 2.1%。因此,如果 您添加 20 个索引,您的插入将 减慢 40-50%。但是你的选择 将快 10-100 倍。
那么添加很多索引可以吗? - 它 取决于:) 我给了你我的结果 - 你 决定!
【讨论】:
这不应该被视为没有所有细节的预言。尤其是因为您无法将一项操作的性能增益/损失乘以另一操作。基础保持不变:添加更多索引,由于索引重新创建,您的插入最终会变慢。【参考方案8】:最终需要多少索引取决于在数据库服务器上运行的应用程序的行为。
一般来说,插入的次数越多,索引就越痛苦。每次插入时,都必须更新包含该表的所有索引。
现在,如果您的应用程序有相当多的读取量,或者如果它几乎是所有的读取量甚至更多,那么索引就是要走的路,因为它将以极少的成本显着提高性能。
【讨论】:
【参考方案9】:在我看来没有一成不变的答案,这类事情属于“性能调优”。
可能是您的应用所做的一切都是通过主键查找的,或者可能是相反的,因为查询是通过不受限制的字段组合完成的,并且任何特定的组合都可以在任何给定时间使用。
除了索引之外,还有重新组织您的数据库以包括计算的搜索字段、拆分表等 - 这实际上取决于您的负载形状和查询参数,查询需要“真正”返回多少/什么数据。
如果您的整个数据库前面是存储过程门面,则翻转会变得更容易一些,因为您不必担心每个临时查询。或者您可能对将访问您的数据库的查询类型有深入的了解,并且可以将调整限制在这些查询范围内。
对于 SQL Server,我发现数据库引擎优化顾问很有用 - 您设置“典型”工作负载,它可以就添加/删除索引和统计信息提出建议。我确信其他数据库也有类似的工具,无论是“官方”还是第三方。
【讨论】:
【参考方案10】:这确实是一个比实际更理论的问题。索引对性能的影响取决于您拥有的硬件、Oracle 的版本、索引类型等。昨天我听说 Oracle 宣布了由 HP 制造的专用存储,它应该在 11g 数据库上运行速度提高 10 倍。 至于你的情况,可以有几种解决方案: 1.拥有大量索引(> 20)并每天(每晚)重建它们。如果表每天有数千次更新/删除,这将特别有用。 2. 对您的表进行分区(如果这适用于您的数据模型)。 3. 为新的/更新的数据使用单独的表,并运行一个将数据组合在一起的每晚进程。这将需要更改您的应用程序逻辑。 4. 如果您的数据支持,请切换到 IOT(索引组织表)。
当然,这种情况可能还有更多解决方案。我给你的第一个建议是将数据库克隆到开发环境,并对其进行一些压力测试。
【讨论】:
我不明白重建索引会有什么帮助,或者 IOT 会有什么帮助。 IOT - 如果可以重新设计应用程序,以便使用新的用户定义数据类型,那么 IOT 将节省索引表的开销。这可能不是这里的情况。这真的取决于。重建索引——以防有很多索引,而新数据没有被索引。 IOT 仍然是一个索引结构,块分割的开销比常规索引要多。 “重建索引——以防有很多索引,而新数据没有被索引”......你说的是哪个 RDBMS 不会为新条目自动维护索引? 大卫 - 你当然是对的。我将它与 SQL Server 仅按需求索引全文搜索的能力相结合。希望 Oracle 拥有它,因为它在这种情况下可能很有用。我建议坚持其他两个建议。【参考方案11】:如果您主要进行阅读(并且很少更新),那么确实没有理由不对您需要索引的所有内容进行索引。如果您经常更新,那么您可能需要谨慎对待您拥有的索引数量。没有硬性数字,但是当事情开始放缓时,您会注意到。确保您的聚集索引是基于数据最有意义的索引。
【讨论】:
【参考方案12】:您可能会考虑的一件事是构建索引以针对标准搜索组合。如果经常搜索 column1,并且经常将 column2 与它一起使用,并且 column3 有时与 column2 和 column1 一起使用,那么在 column1、column2 和 column3 上按该顺序排列的索引可以用于这三种情况中的任何一种,尽管它是只需维护一个索引。
【讨论】:
【参考方案13】:更新基础表时,索引会产生成本。索引在用于加速查询时提供了好处。对于每个索引,您需要平衡成本与收益。如果没有索引,查询会慢多少?跑得更快有多大好处?您或您的用户能否容忍索引丢失时的缓慢速度?
您能容忍完成更新所需的额外时间吗?
您需要比较成本和收益。这对你的情况来说是特别的。超过“太多”阈值的索引没有神奇的数字。
还有存储索引所需的空间成本,但您说过在您的情况下这不是问题。在大多数情况下也是如此,因为磁盘空间变得如此便宜。
【讨论】:
【参考方案14】:有多少列? 我一直被告知要制作单列索引,而不是多列索引。所以没有比列数更多的索引,恕我直言。
【讨论】:
【参考方案15】:真正归结为,不要添加索引,除非您知道(这通常意味着收集使用情况统计信息)它的使用频率远高于更新频率。
任何不符合该标准的索引都将花费您更多的重建成本,而不是在使用它的奇怪情况下不使用它所造成的性能损失。
【讨论】:
【参考方案16】:Sql server 为您提供了一些很好的工具,可以让您查看实际使用了哪些索引。 本文http://www.mssqltips.com/tip.asp?tip=1239 提供了一些查询,让您可以更好地了解索引的使用量,而不是更新量。
【讨论】:
【参考方案17】:它完全基于 Where 子句中使用的列。 作为规则的拇指,我们必须在外键列上建立索引以避免死锁。 AWR 报告应定期分析以了解索引的需求。
【讨论】:
在外键列上建立索引以避免死锁?您是否有参考资料解释了这种情况的原因和方式?以上是关于多少数据库索引太多了?的主要内容,如果未能解决你的问题,请参考以下文章