MSSQL:为什么这个索引比另一个快10倍?

时间:2014-05-24 08:05:15

标签: sql sql-server performance nhibernate database-design

我发现了一个非常奇怪的行为,我必须解释。我们有一个包含大约450,000个条目的简单表(MSSQL 2008 R2)。

此表的索引非常简单:

索引#1包含:

[OwnerUserID] -> int, 4 byte
[TargetQuestionID] -> int, 4 byte
[LastChange] -> date,  8 byte

索引#2包含:

[LastChange] is a date, 8 byte
[OwnerUserID] is an int, 4 byte
[TargetQuestionID] is an int, 4 byte

正如您所看到的,区别仅在于列的顺序略有不同;在两个索引中,叶子具有相同的大小,16个字节(远远超过我在大型数据库上做过一些DBA)

查询很简单:

Query #1:
- Asks just for the last entried element ( top(1) ) ordered by LastChange, so it takes only LastChange into account

Query #2:
- Asks just for the last entried element ( top(1) ) entried for a distinct OwnerUserID, so it takes OwnerUserID and LastChange into account

结果是:

对于查询#1,索引#1超级慢,虽然我认为它应该没问题,因为数据叶子真的不大(16字节)

索引#2对查询#2来说超级慢(但由于它考虑了两个值,OwnerUserID + LastChange = 8个字节,我没有看到任何理由为什么它应该慢得多/更快)

我们的想法是只有一个索引,但由于每个查询场景的性能相差10到11倍,我们最终并行创建了这两个索引,我们认为我们可以选择一个 - 因为索引并不是那么大/复杂,你实际上认为列顺序的这种细微差别会伤害。

所以,现在我们浪费了双倍的空间,因为桌子每天增加10k行,我们将来会在某处出现磁盘空间问题......

首先,我认为这是因为一些内部的NHibernate问题,但我们检查了性能监视器,结果绝对可重现。

似乎MSSQL与索引的性能在很大程度上取决于datetime-columns的使用,因为这个简单的例子表明这可能会导致整个性能崩溃: - /

1 个答案:

答案 0 :(得分:2)

通常使用索引来进行快速二进制搜索,而不是慢速顺序搜索。为实现此目的,它们按排序顺序或树形存储索引键。但是只有在知道密钥的开始时才能进行二分搜索,因此元素的顺序很重要。在你的情况下,这意味着:

  • 查询#1需要具有最低LastChange的记录。可以使用索引来优化此查询,该索引以LastChange开头,例如,排名第2。使用索引#1,它需要回退到顺序搜索。
  • 查询#2首先需要查找所有唯一的OwnerIds,以及以OwnerId开头的索引可以在这里提供帮助。然后它需要找到特定OwnerId的最低LastChange。索引#1在这里没有帮助,因为索引中的下一个字段不是LastChange。如果同一OwnerId有大量记录,则索引#2可能会有所帮助。否则它可能会进行顺序搜索。

因此,对于索引,字段的顺序应与查询匹配。此外,您可能需要更新统计信息,以便查询计划员知道是否更好地执行顺序搜索(每个OwnerId几个条目)或使用索引#2(每个OwnerId有很多条目)。我不知道是否以及如何使用mysql,只能从postgresql中知道它。

索引始终是一种权衡:它会降低插入速度,但会加快查询速度。所以它在很大程度上取决于你的应用程序你有多少指数以及它们将如何构建。