帮助理解索引上的多个列?

时间:2009-09-16 16:43:13

标签: sql-server tsql indexing

假设我有一个名为“table”的表,我有3列,a,b和c。

在a,b列上有非聚集索引是什么意思?

列a,b上的非聚簇索引与列b上的非聚簇索引相同吗? (注意顺序)。

此外,列a上的非聚簇索引是否与a上的非聚簇索引相同?

我正在查看网站的sqlserver性能,他们有这些dmv脚本,它会告诉你,如果你有重叠的索引,我相信它是说a上的索引与a,b相同,所以它是多余的。关于索引这是真的吗?

最后一个问题是为什么聚集索引放在主键上。大多数情况下,不会查询主键,因此聚集索引不应位于查询最多的列上。我可能在这里遗漏了一些东西,比如在主键上加速连接?

很好的解释。我应该把它变成一个wiki并更改标题索引解释吗?

5 个答案:

答案 0 :(得分:16)

答案 1 :(得分:3)

(a, b)上的非聚集索引是表格的一部分的“副本”,其行在a然后在b上排序包含对原始行的引用。

这样可以帮助您运行查询:

SELECT  *
FROM    mytable
WHERE   a = @A
        AND b = @B

,这个:

SELECT  *
FROM    mytable
ORDER BY
        a, b

,这个:

SELECT  *
FROM    mytable
WHERE   a = @A
ORDER BY
        b

和其他许多人。

例如,我们有一个这样的表:

#       col1    col2    col3
1       1       1       1
2       1       4       8
3       7       2       3
4       3       3       9
5       8       9       4
6       2       2       7
7       5       3       5
8       3       9       4

如果我们在(col2, col3)上创建索引,它将包含以下数据:

col2    col3    #
1       1       1
2       3       3
2       7       6
3       5       7
3       9       4
4       8       2
9       4       5
9       4       8

,我。即首先在col2上排序,然后在col3上排序,然后排在对行的引用上。

很容易看出此索引也是col2上的索引((col2, col3)上的排序意味着仅在col2上排序)。

订单很重要,因此如果我们在(col3, col2)上创建索引,行的排序方式会有所不同:

col2    col3    #
1       1       1
2       3       3
9       4       5
9       4       8
3       5       7
2       7       6
4       8       2
3       9       4

此索引也是col3的索引。

如果我们想在(col2, col3)的某个范围内找到行,我们只需从有序数据中取一个切片:

SELECT  col2, col3
FROM    mytable
WHERE   col2 BETWEEN 2 AND 3

col2    col3    #
1       1       1
----
2       3       3
2       7       6
3       5       7
3       9       4
----
4       8       2
9       4       5
9       4       8

很容易看到我们无法使用此索引在col3上使用此切片,因为col3不是自行排序的。

上面提到的“引用”是行的RID(指向表空间中的位置的指针),如果表本身是非群集的,或者表的簇密钥的值(如果表)是聚集的。

聚集索引不会创建值的卷影副本。相反,它会重新排列表格行本身。

如果您在上面的(col2, col3)上创建聚簇索引,它只会重新排列表行:

#       col1    col2    col3
1       1       1       1
3       7       2       3
6       2       2       7
7       5       3       5
4       3       3       9
2       1       4       8
5       8       9       4
8       3       9       4

因此,群集或非群集是一种存储方法而不是索引。

Oracle中,这称为index-organized table(行已排序),而不是heap-organized table(行未排序)。

答案 2 :(得分:2)

索引A,B与索引B不同,A

这是因为索引是按特定的排序顺序组织的。因此,假设您需要使用以下WHERE子句进行搜索

WHERE A='somecrit' AND B='SomepartialCrit%'  -- notice the wildcard

A,B索引在解析查询时非常有效,但如果是

WHERE   A='SomepartialCrit%'  AND B='somecrit'

(A,B)指数只能部分帮助(可能比全表扫描更好但不是最佳......),因此(B,A)指数可以拯救......

对于使用包含A和B作为完全匹配(无通配符)的查询的情况,可以以等效方式使用索引(效率方面),尽管一个特定索引的选择可以由其他部分驱动查询,如ORDER BY子句等。

A上的索引与A,C 上的索引不同 对于A,C上的索引可用于解析涉及A和C标准的查询,并且A,C索引也可用于“覆盖”SELECT子句或其部分,即:如果SELECT子句只包括A列和C列(来自这个特定的表),SQL可以提供结果而不必从表中获取数据,它只能从索引中获取A和C值。

“冗余”索引是件坏事吗?

如上所述,额外的索引可以帮助更有效地解决SELECT查询。在不利方面,他们a)使用存储空间和b)使INSERT,UPDATE和DELETE查询效率降低(因为需要在更多地方添加/更改/删除新的/更新/删除的值。

因此,根据可用的可用存储空间和用例(一些大多数只读数据库可以拥有大量索引而不会损害性能,具有频繁插入的数据库)可以看到正确的平衡问题。性能下降太多指数)

关于聚集索引

见Joel Coehoorn的解释 不,给定表的聚簇索引不需要基于主键。选择一个好的聚集索引(或者确实决定使用聚簇索引)是一个部分科学的部分艺术过程,其范围超出了这个简短的响应。

答案 3 :(得分:2)

  

列a,b上是非聚集索引   与非聚集索引相同   列b,a? (注意顺序)。

NO!订单很重要。如果你在(a,b)上有一个非聚集索引,你可以使用这个,如果你的WHERE子句对a和b有限制 - 或者它只对a有限制(但如果只是对b)进行检查。

  

此外,是非聚集索引   列a与非聚簇相同   索引a,c?

不,不是 - 但如果SQL Server查询优化器在“a”上遇到带有WHERE子句的查询,它将使用此非聚集索引。

马克

答案 4 :(得分:2)

将索引视为电话簿。通常电话簿按姓氏,名字,街道排序。因此,如果你想找到Joe Smith,101 Main Street的电话号码,你打开S for Smith的电话簿,然后你查找Smith下的所有Joes,寻找住在101 Main Street的Joe Smith,然后你找到电话号码。

电话簿的订购方式可以不同,例如街道,名字,姓氏。然后你首先查看Main Street,然后是Joe,最后是Smith。如果你只想找到一个人的号码,那就快了。

如果您想列出居住在主街并且名字为Joe的所有人的电话号码,差异就变得很重要了。对于普通的电话簿,这是一个苦差事:你必须遍历所有的姓氏,找出姓氏的Joes,以及他们是否住在Main Street。要做到这一点,你必须浏览整本电话簿。但是如果索引顺序是street,firstname,lastname,那么任务几乎是微不足道的:查找Main Street,Joe,并复制所有姓氏和他们的电话号码。方式更快。<​​/ p>

此外,如果您只对名称感兴趣,那么电话簿列出街道的事实也无关紧要。如果你想找到所有Joe Smiths的电话号码,你需要一个按姓氏,名字(或名字,姓氏)排序的电话簿。你不在乎电话簿是否所有Joe Smiths都是街上订购的。从这个意义上说,(姓氏,名字,街道)上的索引包含(姓氏,名字)的索引。

所以:index(a,b,c)不等于(c,a,b),如果你有(a,c)你不需要另一个(a)