多个单字段索引与多字段索引

时间:2012-03-15 18:37:00

标签: sql sqlite

我知道在StackOverflow上有类似的问题,但在我的表上测试不同的索引之后,我想我不太明白索引是如何工作的,如果有人可以解释我在我身上遇到的行为,我会喜欢它查询表现。

我正在使用此查询作为示例,我将尝试详细解释它:

 SELECT ss1.PlayerID, ss1.Name, ss1.Series, ss1.LanesNum, ss1.Date, ss1.LeagueName, ss1.Season FROM SeriesScores ss1
          JOIN (SELECT Series, Gender, LanesNum, Bowlout, Season FROM SeriesScores
          WHERE Gender = ? AND LanesNum = ? AND Series > -1 AND Bowlout = 'No' AND Season = '2011-2012'
          ORDER BY Series DESC LIMIT 0,?) as ss2
          USING(series, gender, lanesNum, bowlout, season)
          ORDER BY ss1.Series DESC

此查询用于获取保龄球中每对车道在给定赛季中为男性和女性球员打出的最高系列。

我正在加入表格而不是使用MAX聚合函数,因为如果在一对给定的通道上有一个平局,我希望所有的名字出现。

基本上,我连接所有匹配内部SELECT返回的字段。内部SELECT返回给定性别和一对给定车道的前X个玩家。

USING部分确保只有那些没有被淘汰的球员,具有相同的性别,系列,lanesNum和赛季,因为我正在寻找。然后我按最高系列订购它们到最低系列。

此查询位于for循环中,男性运行12次,女性运行12次(保龄球中心12对通道),只有lanesNum和性别参数发生变化。

然后我将所有结果放在Java中的两个不同的向量中,以在应用程序中显示结果(一个用于男性,一个用于女性)。

没有任何索引,运行所有内容大约需要11秒,包括将结果放在向量中以及所有这些内容。 (男性12次查询为5.5秒,女性为12次)。

对于(gender,lanesNum,series)的索引,整个过程需要0.04秒,这太棒了,因为这对我的需求而言是一个超过可接受的速度。

我使用了那个索引,因为那些是我在WHERE子句中使用的所有最重要的字段,但我不明白为什么它会加速这么多,因为我尝试了其他的东西,并使用其他一些实际制作的索引我的查询SLOWER超过100%。另外,我想知道如果我将“bowout”和“season”添加到该索引中,我是否会得到更快的查询。

我想首先在系列上尝试单列索引并测试性能。这是使所有这些查询总共需要22秒的索引。

我得出的结论是,我不明白我应该在哪里使用索引,何时应该在多个字段上使用它们,或者在单个字段上使用多个索引等。另外,我不明白如何使用(错误的)索引实际上会使性能变差。

1 个答案:

答案 0 :(得分:1)

仅针对一个查询过于强烈地优化索引会降低其他查询(以及现实世界的应用程序或其下一版本)的速度。但是,让我们将其作为分析指数表现的练习。

索引以多种方式影响查询性能;它们的存在实际上可以完全改变数据库服务器用于获取数据的算法。一个很好的概述是here,但是由于您的查询很简单,并且您实际上在数据库中只有很少的相关索引(您看到的那个,并且还自动创建索引以支持表的主键),我们可以简化故事。

一个好的索引可以更快地交叉引用表之间的数据。理想情况下,它包含USING和WHERE子句中的列,并且足以在大多数情况下引用其表中的唯一行。如果它包含less,它可能仍然被数据库服务器使用,但是必须逐个访问剩余的行。

一个伟大的索引不仅包含所有这些,而且它还包含您将从表中选择的所有数据(是的,当两个表由于自连接而实际上是相同的物理表时,这是有意义的;数据库服务器仍然处理好像它是两个不同的表,顺便说一下,具有相同的数据)。这种“完全覆盖索引”的好处是数据库服务器根本不必访问它的表;所有列都在索引中可用。

索引中的列顺序很重要。特别重要的是索引中最左边的列出现在USING子句或WHERE子句中;否则索引几乎无法使用,因为单个查找的匹配数据可以出现在该索引的许多位置。它也应该是高度选择性的(表中有许多不同的值)。现在做一些实验来看第一手资料。

出于这个原因,我建议的第一个选择索引是series, gender, lanesNum, bowlout;但你的查询也很好。

显式创建多个索引没有多大用处。在查询执行期间,基本上没有多少用途,因为您的查询非常简单。因此,最有用的一个将被认为是胜利而所有其他人将被忽略。

对于你的上一个问题:有些人认为多余的索引只会降低UPDATE,INSERT和DELETE语句的速度(因为它们会带来更新索引的开销),但事情并非那么简单。由于数据库服务器会考虑多种算法来计算您的查询(有两个逻辑表可供使用,而自动和显式索引要使用或不使用),它可能会选择错误的计划:索引在不知道数据的情况下可能看起来很诱人表中的分布,但鉴于分布,会产生相反的效果。

实际上有一种方法可以让数据库服务器分析数据并记录一些统计信息,这些统计信息将极大地帮助它合理地优化您的后续查询,并可能避免任何22秒执行您的查询(直到您将数据更改为统计数据将不再适用)。那是ANALYZE命令。更改索引后每次都会发出它,以便最好地查看后续的sqlite性能。在生产数据库中,安排ANALYZE每晚执行,这样您的数据库不会随着时间的推移逐渐减慢,或者在添加无害的无用索引后突然减慢。