复合索引如何工作?


69

我创建综合指数(指数表上你的数学民间)之前,他们是如何工作的假设。我只是好奇我的假设是否正确。

我假设当您列出索引的列顺序时,您还要指定如何对索引进行分组。举例来说,如果你有列ab以及c和您指定的指数相同的顺序a ASCb ASC以及c ASC随后产生的指数基本上将许多指标在每一个“组” a

这个对吗?如果不是,结果索引实际上将是什么样?


参见此处:SQL Server涵盖索引的详细说明
SQLMenace

在我看来,这似乎是一个综合索引。创建NONCLUSTERED索引idx_PeopleTest_Name_Id_FavoriteColor ON PeopleTest(名称,Id,FavoriteColor)
SQLMenace

Answers:


84

复合索引的工作方式与常规索引相同,不同之处在于它们具有多值键。

如果在字段(a,b,c)上定义索引,则记录将首先在a上排序,然后在b上排序,然后在c上排序。

例:

| A | B | C |
-------------
| 1 | 2 | 3 |
| 1 | 4 | 2 |
| 1 | 4 | 4 |
| 2 | 3 | 5 |
| 2 | 4 | 4 |
| 2 | 4 | 5 |

32
另请注意,索引存储为Btree,因此(a,b,c)索引将有助于搜索(a)和(a,b),但不适用于其他搜索,例如(b)或(b, C)。
geek-merlin

35

复合索引就像字典中的普通字母索引,但涵盖两个或多个字母,如下所示:

AA - page 1
AB - page 12

等等

表行首先由索引中的第一列排序,然后由第二列等排序。

当您按两列或第一列进行搜索时,它是有用的。如果您的索引是这样的:

AA - page 1
AB - page 12
…
AZ - page 245
BA - page 246
…

您可以使用它来搜索2字母(= 2表中的列),或者像搜索一个字母的普通索引一样:

A - page 1
B - page 246
…

请注意,在使用字典的情况下,页面本身按字母顺序排列。那是CLUSTERED索引的一个例子。

在普通的非CLUSTERED索引中,对页面的引用是有序的,就像在历史书中一样:

Gaul, Alesia: pages 12, 56, 78
Gaul, Augustodonum Aeduorum: page 145
…
Gaul, Vellaunodunum: page 24
Egypt, Alexandria: pages 56, 194, 213, 234, 267

当您有ORDER BY两列或更多列时,也可以使用复合索引。在这种情况下,一个DESC子句可能会派上用场。

请参阅我的博客中有关DESC在复合索引中使用子句的文章:


18

索引的最常见实现是使用B树来进行某种程度的快速查找以及合理的快速范围扫描。这里要解释的太多了,但这是B树上的Wikipedia文章。没错,在创建索引中声明的第一列将是结果B树中的高阶列。

在高阶列上的搜索相当于范围扫描,而B树索引对于此类搜索可能非常有用。看到这种情况的最简单方法是类比您尚未转换为联机目录的库中的旧卡目录。

如果您正在寻找姓氏为“ Clemens”的“作者”的所有卡片,则只需转到作者目录,然后快速找到前面有“ CLE-CLI”的抽屉。那是正确的抽屉。现在,您在该抽屉中进行了一种非正式的二进制搜索,以快速找到所有上面写着“ Clemens,Roger”或“ Clemens,Samuel”的牌。

但是,假设您想查找名字为“ Samuel”的作者的所有卡片。现在,您将面临困境,因为这些卡片没有在“作者”目录中的一个地方聚集在一起。数据库中的复合索引也会发生类似的现象。

不同的DBMS在优化器检测索引范围扫描以及准确估算其成本方面有多高明。并非所有索引都是B树。您必须阅读特定DBMS的文档才能获取真实信息。


谢谢,我一直在努力思考这个问题,没有明确的答案。“在高阶列上进行搜索相当于进行范围扫描”,但是如果索引涵盖2列,并且在范围查询中指定了这两列,例如“ ColumnA <threshold1 AND columnA> threshold 2 AND columnB <threshold3 AND “ columnB> threshold4”,看来oracle必须在B树上花费MULTIPLE范围扫描,对吗?那么如果我们在复合索引中有很多列,则必须进行许多范围扫描,并且索引的有效性会大大降低
teddy teddy 2012年

在我的回答中,我的意思是ColumnA = value相当于一个范围扫描,因为可能有许多条目对于ColumnA都具有正确的值,但是对于ColumnB具有不同的值。您概述的情况是完全不同的。它可能仍然是范围扫描,但是范围可能涉及索引中很大比例的条目。范围越大,索引节省的时间就越少。如果使用索引的值下降得太低,则优化器可能会选择其他策略。
Walter Mitty

4

不会。结果索引将是单个索引,但带有复合键。

KeyX = A,B,C,D; KeyY = 1,2,3,4;

索引KeyX,KeyY实际上是:A1,A2,A3,B1,B3,C3,C4,D2

这样一来,如果您需要通过KeyXKeyY那将很快并且将使用单个索引。类似于SELECT ... WHERE KeyX =“ B” AND KeyY = 3。

但重要的是要了解:WHERE KeyX =吗?请求使用该索引,而WHERE KeyY =?完全不会使用这样的索引。


最后一个断言在Oracle上是不正确的。请参阅stackoverflow.com/questions/57878/…(忽略-错误-可接受的答案)。
Hobo

@Hobo:1.在大多数RDBMS中,跳过扫描不可用。2.在大多数情况下,这将非常慢,仅比简单的表扫描快(有时甚至慢)(在极少数情况下,它确实会有所帮助)。Oracle中没有魔术。记住这是一个好规则-如果您的条件不是仅使用索引中的顶级列,则不要依赖复合索引(这是创建大型复合索引的常见错误)。
马什

@Mash点数。绝对不是说跳过扫描是灵丹妙药,只是在某些情况下KeyY =?使用索引。想通了最好给一个完整的图片。至于速度,希望优化器会选择合适的方法(尽管像往常一样会测量而不是假设(如有疑问))
Hobo

@Hobo。我认为这是一个新手问题-最好不要提供完整图片,而首先要较小。作为优化器,您知道-许多研究表明,Oracle优化器的AI实际比其应有的智能,并且Oracle 10在大多数情况下在实践中都比Oracle 9慢,这仅仅是因为它在理论上过于智能。
马什
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.