2014-05-24 54 views
0

我发现了一个非常奇怪的行为,我必须解释。我们有一个简单的表格,大约有450.000个条目(MSSQL 2008 R2)。MSSQL:为什么这个索引比其他索引快10倍?

此表的索引是很简单的:

指数#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超级慢,虽然我认为这应该是OK,因为数据叶子是真的不大(16个字节)

指数#2是用于查询#2超慢(但由于它需要考虑两个值,OwnerUserID + LastChange = 8个字节,我没有看到任何为什么它应该更慢/更快)

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

所以,现在我们是在浪费一倍的空间,因为该表由每天1万行左右的增长,我们将磁盘空间问题的地方在未来...

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

好像与指标MSSQL性能高度依赖的datetime-列的使用,因为这个简单的例子表明,这可能崩溃全性能: -/

+0

检查执行计划。 –

+0

嘿嘿,那是真的 - 我们只检查了SQL分析器,看看它需要多长时间,但不是执行计划: -/ – johngrinder

回答

2

通常被用于索引来进行快速的二进制搜索可能的,而不是缓慢的顺序搜索。为了达到这个目的,他们按照排序顺序或树形结构存储索引键。但是,只有密钥的开始是已知的,因此二进制搜索才是可能的,因此元素的顺序很重要。在你的情况下,这意味着:

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

因此,对于索引,字段的顺序应该与查询相匹配。此外,您可能需要更新统计信息,以便查询计划人员有一个想法,即如果顺序搜索更好(每个OwnerId少数条目)或使用索引2(每个OwnerId大量条目)。我不知道是否以及如何用mysql来完成,只能从postgresql知道。

索引总是一个折衷:它会减慢插入速度,但会加速查询。所以它高度依赖于你的应用程序你有多少指数以及它们将如何构建。

+0

此外:使用您提供的工具,而不是问一个问题。查看查询计划 - 他们很乐意向您展示使用哪些索引。管理人员Studi可以很好地监视他们。 – TomTom

+0

TomTom,如上所述:好主意 - 我们没有检查的执行计划,只有SQL Profiler ... – johngrinder

相关问题