2009-04-27 83 views
49

我已经在桌子上创建了复合索引(索引,对于你的数学民谣),并假设它们是如何工作的。我只是好奇,如果我的假设是正确的或没有。组合索引如何工作?

我假设当你列出索引列的顺序时,你也指定了索引如何分组。例如,如果您有a,bc列,并且您按相同顺序指定索引a ASC,b ASCc ASC,则结果索引对于a中的每个“组”将基本上是许多索引。

这是正确的吗?如果不是,那么结果指数实际上会是什么样子?

+0

请参阅这里:[SQL Server覆盖索引](http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/sql-server-covering-indexes)一个很好的解释 – SQLMenace 2009-04-27 20:03:17

+0

这看起来像一个复合索引给我CREATE NONCLUSTERED INDEX idx_PeopleTest_Name_Id_FavoriteColor ON PeopleTest(Name,Id,FavoriteColor) – SQLMenace 2009-04-27 20:08:33

回答

54

复合索引就像常规索引一样工作,除了它们具有多值键。

如果您在字段(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 | 
+7

请注意,索引是作为Btree存储的,因此(a,b,c)索引将有助于在(a)和(a,b)上进行搜索,但在其他搜索(如(b)或(公元前)。 – aexl 2016-04-30 17:53:06

3

否。结果索引将是单索引但带有复合键。

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

指数KeyX,KeyY会实际上是:A1,A2,A3,B1,B3,C3,C4,D2

这样的情况下,你需要通过KeyX KeyY找到的东西 - 这将是快速并将使用单个索引。就像SELECT ... WHERE KeyX =“B”AND KeyY = 3.

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

+0

最后一个断言在Oracle上不是真的。请参阅http://stackoverflow.com/questions/57878/sql-oracle-when-indexes-on-multiple-columns-can-be-used(忽略 - 错误 - 接受的答案)。 – Hobo 2009-04-27 20:26:11

+0

@Hobo:1.在大多数RDBMS中,跳过扫描不可用。 2.在大多数情况下,速度非常慢,比简单的表扫描速度快(有时甚至更慢)(在非常罕见的情况下,它确实会有所帮助)。甲骨文没有魔力。只需记住一条好规则 - 如果您的标准不仅仅使用索引的顶级列(这是创建大型复合索引的常见错误),请不要依赖复合索引。 – Mash 2009-04-27 20:43:05

+0

@拍摄积分。绝对不会说跳过扫描是一个银弹,只是有些情况下KeyY =? _将使用索引。想想最好尽可能地给出完整的图片。至于速度,希望优化器会选择合适的方法(尽管如往常一样,如果有疑问将会测量而不是假设) – Hobo 2009-04-27 21:40:48

17

索引的最常见的实现使用B树,以允许一定程度的快速查找,并且还相当快速范围扫描。这里解释太多了,但这里是关于B-trees的维基百科文章。你是对的,你在创建索引中声明的第一列将是结果B-树中的高阶列。

对高阶列的搜索相当于一个范围扫描,而B树索引对于这样的搜索非常有用。最简单的方法是通过类比旧库卡中的尚未转换为在线目录的旧卡目录。

如果您正在寻找所有名字为“Clemens”的作者名片,只需转到作者目录,并很快找到一个在前面写上“CLE- CLI”的抽屉。这是正确的抽屉。现在你在抽屉里做一种非正式的二进制搜索,快速找到所有名为“Clemens,Roger”或者“Clemens,Samuel”的卡片。

但是,假设您想为名为“Samuel”的作者找到所有卡片。现在你上了小溪,因为这些卡片不是聚集在作者目录的一个地方。数据库中的复合索引也会出现类似现象。

不同的DBMS在其优化器在检测索引范围扫描方面的聪明程度不同,并准确估计其成本。并不是所有的指数都是B树。您必须阅读您的特定DBMS的文档才能获得真实的信息。

+0

谢谢,我一直在想这个问题很难,没有明确的答案。 “对高阶列的搜索相当于范围扫描”,但是如果索引覆盖2列,并且在列范围查询中指定了两列,如“ColumnA threshold 2 AND columnB threshold4“,那么oracle似乎不得不在B树上花费多次范围扫描,对吧?那么如果我们在复合索引中有很多列,我们必须做很多范围扫描,并且索引的有效性会大大降低 – 2012-05-15 16:52:38

+0

在我的答案中,我的意思是说ColumnA = value相当于一个范围扫描,因为可能有很多条目都具有适合于ColumnA的值,但对于ColumnB具有不同的值。你概述的情况完全不同。它可能仍然是范围扫描,但范围可能涉及索引中大部分条目。范围越大,索引节省的越少。如果使用索引的值降低,优化器可能会选择不同的策略。 – 2013-02-09 02:00:44

28

综合指数是像在字典中一个普通的字母索引,但覆盖两个或多个字母,这样的:

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条款:

0

我的理解是,复合索引工作就像普通索引,除非他们有个值键。如果您在字段(a,b,c)上定义索引,由于复合索引将存储在BinaryTree中,因此索引仅在搜索组合后才起作用。

ABC 
AB 
A 

例如创建用于复合索引,b和c场等价于创建用于A,AB和abc单独的索引。