数据库索引:好事,坏事还是浪费时间?

时间:2010-11-24 14:35:02

标签: sql database-design cross-platform

此处通常建议添加索引作为性能问题的补救措施。

(我说的只是阅读和查询,我们都知道索引会使写入速度变慢)。

多年来,我在DB2和MSSQL上多次尝试过这种补救措施,结果总是令人失望。

我的发现是,无论多么“明显”,索引会让事情变得更好,但事实证明,查询优化器更聪明,而我精心挑选的索引几乎总是让事情变得更糟。

我应该指出,我的经历主要涉及小桌子(< 100'000行)。

任何人都可以提供一些关于索引选择的实用指南吗?

正确的答案是建议列表如下:

  • 从不/始终索引小于/超过NNNN记录的表
  • 从不/始终考虑多字段键上的索引
  • 从不/始终使用聚簇索引
  • 从不/始终在单个表上使用多于​​NNN索引
  • 永远/永远在[我需要了解的一些神奇条件]
  • 时添加索引

理想情况下,答案会给出一些有益的例子。

8 个答案:

答案 0 :(得分:18)

索引有点像化疗...太多了它会杀死你......太少而且你死了......做错了,你就死了。你必须知道多少,多少次,多少才能使它不会杀死你。

您的硬件,平台,环境,负载都发挥作用。所以回答你的问题..

是的,有时可能。

答案 1 :(得分:12)

根据经验,主键和外键需要编入索引。通常只通过定义主键来索引主键,但FK不在每个数据库中(它们肯定不在SQL Server中,我不能真正代表其他dbs)。您将在连接中使用这些,因此定义这些通常对性能至关重要。

现在,如果你经常在where子句中使用字段,他们可以从索引中受益,并提供以下几点:

  • 首先,该字段必须具有范围 值。有点字段或字段 只有2或3个值几乎不会 使用索引。

  • 其次,您编写的查询必须是sargable。那就是它们必须设计为使用索引。我怀疑如果你从来没有从索引的可能候选者那里获得性能改进,那么你可能会有一些不可思议的查询。例如,将“WHERE Name like'%Smith'”作为where子句。在不知道第一个字符的情况下,优化器无法使用索引。

小表很少从索引中获益。如果优化器可以将整个内容保存在内存中,那么这样做通常会更快。如果您使用的是数百万条记录表,您会发现索引非常重要。

索引可能非常复杂,如果您对该主题感兴趣,我建议您获得一本关于性能调优特定数据库的好书,并深入了解它们。

答案 2 :(得分:5)

从未使用的索引是浪费磁盘空间,以及添加插入/更新/删除时间。最好先定义聚类索引,然后定义 你发现自己编写WHERE子句的其他索引。

我看到一个常见的索引错误是人们想知道为什么当索引被定义为col1 ASC, col2 ASC, col3 ASC时,col2(或col3)上的select会花费这么长时间。如果有多列索引,则WHERE子句必须使用索引中的第一列,或索引中的第一列和第二列,等等。

如果您需要通过col2访问数据,那么您需要一个定义为col2 ASC的附加索引。

对于小域表,执行表扫描有时比使用索引从表中读取行更快。这取决于数据库机器的速度和网络的速度。

答案 3 :(得分:3)

您需要索引。只有索引才能足够快地访问数据。

尽量缩短时间:

  • 为您经常过滤(或分组)的列添加索引。 (例如,州或名称)
  • like和sql函数可能会使DBMS不使用索引。
  • 仅在具有许多不同值的列上添加索引(例如,没有布尔字段)
  • 将索引添加到外键是很常见的,但并不总是需要它。
  • 不要在非常短的表格中添加索引
  • 如果您不知道如何提高性能,请不要添加索引。

最后:查看执行计划,以决定如何优化查询。

您只需为单个关键查询添加索引。在这种情况下,您将准确添加相关查询中所需的索引(多列索引)。

答案 4 :(得分:2)

Always use clustered indexes.

事实上你不能不使用它们。表格中的数据无论如何都会以某种特定的顺序排列在磁盘上,它不能保存为一堆或其他东西。您有机会指定这些数据的确切布局方式。为什么烧它?

当你有一个表附加了新记录并且你发现这些记录中的某些值总是增长时(比如StackOverflow问题编号),请从中创建一个聚簇索引。然后新数据不会插入中间,但基本上会附加到磁盘上的文件,这是一个相对便宜的操作。

答案 5 :(得分:2)

基本上,当数据库正在收集数据时,它的活动索引必须随着该流而发展。表上可能有非常好的索引但是在超过XXX记录之后,同一个表中的相同索引是无用的,在这种情况下它应该被重构。

要拥有优化且快速的数据库,唯一的方法就是始终对其进行监控,并在记录进入时随时重构。

我前段时间得到的真实生活例子是超级快速查询受某些时间范围(A和B之间的created_at)和时间范围不同的超慢查询限制。相同的查询,相同的数据库,相同的应用程序,只有一个时间范围的差异。

答案 6 :(得分:1)

如果一个表应该是一个连接的目标,那么最好在该表上有一个聚簇索引,以便可以通过数据页顺序执行连接。聚簇索引中的列(在某些数据库系统上)将包含在该表的所有其他索引中,因为这些列是索引用于引用表数据的值。为了防止其他索引变得太大,聚簇索引中的列应尽可能地窄,因此最好在聚簇索引中仅使用数字而不是字符数据类型。通常,较少的列比更多的列更好,但请注意,三个int列(每行12个字节)比一个nvarchar(32)列(每行可能64个字节)要好得多。

如果聚簇索引很窄,那么即使在非常大的表上,一些额外的索引也不会对性能产生负面影响。

答案 7 :(得分:0)

似乎你在这里混淆了两个概念。 添加索引 * 通常 可以 只能使读取查询更快,非常非常(几乎从不)更慢。添加索引永远不会强制查询优化器使用它。它只会在认为可以从中受益的情况下使用它,并且通常对这些决策非常聪明。

对于插入/更新,当然,每个索引都会对性能造成更大的影响......但是在频谱的另一端,例如一个只读数据库(就像每月分发的USPS地址数据库),在操作使用中,没有插入/更新,因此附加索引的唯一负面影响是它们占用的磁盘空间。

这与指定完全不同,查询优化器会使用索引,实际上会覆盖它自己会做什么......这可能会使查询变慢。

编辑:编辑消除过度文字读者误解的机会。