SQL Server索引进阶第三篇:聚集索引

 

http://dev.21tx.com/2012/09/11/10901.html

在上一篇文章中,我们已经介绍了非聚集索引相关的内容。在本篇中,我们会介绍与聚集索引相关的话题。

首先,我们综合之前的文章,再来思考一下数据库接收到请求之后(Select,Update,Delete,Insert),获取数据的几种方式:1.仅仅只访问非聚集索引而不访问底层的数据表来获取数据。这种情况只有当索引中包含了所有要请求的数据的时候才发生。

2.通过在索引中查找请求传入的关键字,找到对应的索引信息之后,然后通过索引定位到数据表中的数据列获取额外的信息。

3.不管索引,直接去底层的数据表中获取需要的数据列。

好,我们本篇就关注在第三种获取数据的方法。正如之前一样,我们还是使用SQL Server自带的数据库AdventureWorks,此时,我们只要关注在SalesOrderDetail表,因为表中包含了几十万条数据,可以让我们尽情的测试。另外,和之前一样,还采用了5个与销售和订单相关的表,大家可以参考之前的第一篇文章。

聚集索引示例

首先,我们考虑这样几个问题

1.如果我们在一个没有非聚集索引的表中需找一行数据,所花的成本是多少?

2.在一个无序的表中查找需要的数据的时候是否就意味着对表中的每一行都进行扫描?

3.SQL Server是否可以把表中的数据进行永久的排序,使得数据的检索更快,就和我们之前使用关键字查找非聚集索引结构一样(我们之前的非聚集索引的表中的底层额数据是无序的)?

非聚集索引与底层的数据表不是保存在一起的,非聚集索引中包含了数据表中的一部数据,而且还包含了指向底层数据行的指针。聚集索引则不一样,它是和数据表在一起的。

通 过在表上面建立聚集索引之后,SQL Server就会对表中的数据按照索引键进行排序,并且在每次数据修改的时候都对排序进行维护。现在我们没有必须知道太多的细节,只要知道:建立了聚集索 引的表是一个有序表就行了,而且对于每一行数据都存在一个索引键,使得SQL Server可以通过这个键更快的访问每一行数据。

说了这么多,我们还是来看几个简单的小例子。我们会创建两个表,表中的数据来SalesOrderDetail。一个表上面有聚集索引,一个没有,代码如下:

IF EXISTS (SELECT * FROM sys.tables 
   
WHERE OBJECT_ID = OBJECT_ID('dbo.SalesOrderDetail_index')) 
   
DROP TABLE dbo.SalesOrderDetail_index 
   
GO 
   
   
   
IF EXISTS (SELECT * FROM sys.tables 
   
WHERE OBJECT_ID = OBJECT_ID('dbo.SalesOrderDetail_noindex')) 
   
DROP TABLE dbo.SalesOrderDetail_noindex 
   
GO 
   
   
   
SELECT * INTO dbo.SalesOrderDetail_index FROM Sales.SalesOrderDetail 
   
SELECT * INTO dbo.SalesOrderDetail_noindex FROM Sales.SalesOrderDetail 
   
GO 
   
   
   
CREATE CLUSTERED INDEX IX_SalesOrderDetail ON
   
dbo.SalesOrderDetail_index (SalesOrderID, SalesOrderDetailID) 
   
GO

在SalesOrderDetail没有建立聚集索引之前,数据是这样的:

SQL Server索引进阶第三篇:聚集索引

 

当我们把SalesOrderDetail导入到了dbo.SalesOrderDetail_index表中,然后建立了索引之后,数据是这样的:

SQL Server索引进阶第三篇:聚集索引

 

看完了上面一个小例子,我们就来谈一谈与聚集索引相关的内容。

聚集索引

我们可以在表中任何的列上面建立聚集索引,并不一定非得要在主键上面建立,只不过SQL Server在创建主键的时候,默认的就创建了聚集索引。

另外还有一点需要讲清楚的就是:因为聚集索引的每一个条目就是数据表中的数据行,所以通过聚集索引查找数据的时候,没有必要进行额外的“跳转”或者说没有必要进行所谓的书签查找。

啥都别说了,上个图,先了解一下吧:

SQL Server索引进阶第三篇:聚集索引

 

估计看到这个图之后,很多朋友就越来越糊涂了,因为存在下面的一个疑惑:

不是说:非聚集索引与底层的数据表不是保存在一起的,非聚集索引中包含了数据表中的一部数据,而且还包含了指向底层数据行的指针。聚集索引则不一样,它是和数据表在一起的。

但时从上面图的来看,聚集索引也是和数据表分开保存的!

如果这么问,说明你在思考了;如果没有问,说明你已经懂了。

我承认,之前说的有一些不准确,只要是为了让大家不要再拘泥于细节,有个总体的把握,现在是时候澄清一下内容了。

SQL Server索引进阶第三篇:聚集索引

我们现在应该这样说才算准确:非聚集索引中的数据与底层的数据表不是保存在一起的,因为各自都维护着一份数据,而且非聚集索引中包含了数据表中的一部数据,而且还包含了指向底层数据行的指针。而且在非聚集索引的结构中,最下面的叶子节点不是底层的数据表的数据页。

聚集索引则不一样,因为整个数据表中的数据页是它的节点,所以,聚集索引中包含了整个表的数据。

如何选择合适的列建立聚集索引

到这里,文章可能就和原本的英文有点不同了,以为我们团队认为这里应该加入更多的实际的内容,所以做了大胆的改动。

可以说这个话题是个被讨论很多,也存在很多争论的话题,我们这里主要不会对网络上面的每个论点都做解释,而是从分析的角度出发,帮大家理清本质的东西,好让大家自己决定。

首先解释一下聚集索引和非聚集索引在进行不同操作时的特点,如下表:

SQL Server索引进阶第三篇:聚集索引

另 外,还有一点需要说。如果添加的数据不是添加在数据表中数据页的最后面,那么可能这个插入数据的操作就会涉及到分页操作。此时,分页的波动对非聚集索引影 响小一点。如果数据插入的时候,采用的自动增长列作为主键,而且建立了聚集索引,那么每次数据的插入都会在末尾,那么就不存在这个问题了。

最后要提的一点就是索引列大小的问题。在一个建立了聚集索引的表上面在建立非聚集索引,那么这个非聚集索引会在内部使用聚集索引来定位数据,如果聚集索引所在列很长,那么势必会使得非聚集索引所在空间变大,甚至产生更多的原本不需要的页拆分。

好了,今天就到这里,我们在后续会介绍更多的具体的案例和实践。

posted on 2013-01-10 17:23  奈何倾城  阅读(460)  评论(2编辑  收藏  举报

导航