`

聚簇索引(Clustered Index)和非聚簇索引 (Non- Clustered Index)

 
阅读更多
索引的重要性
数据库性能优化中索引绝对是一个重量级的因素,可以说,索引使用不当,其它优化措施将毫无意义。

聚簇索引(Clustered Index)和非聚簇索引 (Non- Clustered Index)
最通俗的解释是:聚簇索引的顺序就是数据的物理存储顺序,而对非聚簇索引的索引顺序与数据物理排列顺序无关。举例来说,你翻到新华字典的汉字“爬”那一页就是P开头的部分,这就是物理存储顺序(聚簇索引);而不用你到目录,找到汉字“爬”所在的页码,然后根据页码找到这个字(非聚簇索引)。

下表给出了何时使用聚簇索引与非聚簇索引:
动作 使用聚簇索引 使用非聚簇索引
列经常被分组排序
返回某范围内的数据 不应
一个或极少不同值 不应 不应
小数目的不同值 不应
大数目的不同值 不应
频繁更新的列 不应
外键列
主键列
频繁修改索引列 不应


聚簇索引的唯一性
正式聚簇索引的顺序就是数据的物理存储顺序,所以一个表最多只能有一个聚簇索引,因为物理存储只能有一个顺序。正因为一个表最多只能有一个聚簇索引,所以它显得更为珍贵,一个表设置什么为聚簇索引对性能很关键。

初学者最大的误区:把主键自动设为聚簇索引
因为这是SQLServer的默认主键行为,你设置了主键,它就把主键设为聚簇索引,而一个表最多只能有一个聚簇索引,所以很多人就把其他索引设置为非聚簇索引。这个是最大的误区。甚至有的主键又是无意义的自动增量字段,那样的话Clustered index对效率的帮助,完全被浪费了。

刚才说到了,聚簇索引性能最好而且具有唯一性,所以非常珍贵,必须慎重设置。一般要根据这个表最常用的SQL查询方式来进行选择,某个字段作为聚簇索引,或组合聚簇索引,这个要看实际情况。

事实上,建表的时候,先需要设置主键,然后添加我们想要的聚簇索引,最后设置主键,SQLServer就会自动把主键设置为非聚簇索引(会自动根据情况选择)。如果你已经设置了主键为聚簇索引,必须先删除主键,然后添加我们想要的聚簇索引,最后恢复设置主键即可。

记住我们的最终目的就是在相同结果集情况下,尽可能减少逻辑IO。
我们先从一个实际使用的简单例子开始。

一个简单的表:
  1. CREATE TABLE [dbo].[Table1](
  2.   [ID] [int] IDENTITY(1,1) NOT NULL,
  3.   [Data1] [int] NOT NULL DEFAULT ((0)),
  4.   [Data2] [int] NOT NULL DEFAULT ((0)),
  5.   [Data3] [int] NOT NULL DEFAULT ((0)),
  6.   [Name1] [nvarchar](50) NOT NULL DEFAULT (''),
  7.   [Name2] [nvarchar](50) NOT NULL DEFAULT (''),
  8.   [Name3] [nvarchar](50) DEFAULT (''),
  9.   [DTAt] [datetime] NOT NULL DEFAULT (getdate())
复制代码
 

来点测试数据(10w条):
  1. declare @i int
  2. set @i = 1 
  3. while @i < 100000 
  4. begin 
  5. insert into Table1 ([Data1] ,[Data2] ,[Data3] ,[Name1],[Name2] ,[Name3]) 
  6. values(@i, 2* @i,3*@i, CAST(@i AS NVARCHAR(50)), CAST(2*@i AS NVARCHAR(50)), CAST(3*@i AS NVARCHAR(50)))
  7. set @i = @i + 1
  8. end
  9. update table1 set dtat= DateAdd (s, data1, dtat)
复制代码
打开查询分析器的IO统计和时间统计:
  1. SET STATISTICS IO ON;
  2. SET STATISTICS TIME ON;
复制代码
显示实际的“执行计划”:


我们最常用的SQL查询是这样的:
  1. SELECT * FROM Table1 WHERE Data1 = 2 ORDER BY DTAt DESC;
复制代码
先在Table1设主键ID,系统自动为该主键建立了聚簇索引。
然后执行该语句,结果是:
  1. Table 'Table1'. Scan count 1, logical reads 911, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
  2. SQL Server Execution Times:
  3. CPU time = 16 ms, elapsed time = 7 ms.
复制代码
 

然后我们在Data1和DTat字段分别建立非聚簇索引:
  1. CREATE NONCLUSTERED INDEX [N_Data1] ON [dbo].[Table1] 
  2. (
  3. [Data1] ASC
  4. )WITH (SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]
  5. CREATE NONCLUSTERED INDEX [N_DTat] ON [dbo].[Table1] 
  6. (
  7. [DTAt] ASC
  8. )WITH (SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]
复制代码
再次执行该语句,结果是:
  1. Table 'Table1'. Scan count 1, logical reads 5, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
  2. SQL Server Execution Times:
  3. CPU time = 0 ms, elapsed time = 39 ms.
复制代码
 

可以看到设立了索引反而没有任何性能的提升而且消耗的时间更多了,继续调整。

然后我们删除所有非聚簇索引,并删除主键,这样所有索引都删除了。建立组合索引Data1和DTAt,最后加上主键
  1. CREATE CLUSTERED INDEX [C_Data1_DTat] ON [dbo].[Table1] 
  2. (
  3. [Data1] ASC,
  4. [DTAt] ASC
  5. )WITH (SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]
复制代码
再次执行语句:
  1. Table 'Table1'. Scan count 1, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
  2. SQL Server Execution Times:
  3. CPU time = 0 ms, elapsed time = 1 ms.
复制代码
 

可以看到只有聚簇索引seek了,消除了index scan和nested loop,而且执行时间也只有1ms,达到了最初优化的目的。

组合索引小结
小结以上的调优实践,要注意聚簇索引的选择。首先我们要找到我们最多用到的SQL查询,像本例就是那句类似的组合条件查询的情况,这种情况最好使用组合聚簇索引,而且最多用到的字段要放在组合聚簇索引的前面,否则的话就索引就不会有好的效果,看下例:

 

查询条件落在组合索引的第二个字段上,引起了index scan,效果很不好,执行时间是:
  1. Table 'Table1'. Scan count 1, logical reads 238, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
  2. SQL Server Execution Times:
  3. CPU time = 16 ms, elapsed time = 22 ms.
复制代码
而如果仅查询条件是第一个字段也没有问题,因为组合索引最左前缀原则,实践如下:
  1. Table 'Table1'. Scan count 1, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
  2. SQL Server Execution Times:
  3. CPU time = 0 ms, elapsed time = 1 ms.
复制代码
从中可以看出,最多用到的字段要放在组合聚簇索引的前面。

Index seek 为什么比 Index scan好?
索引扫描也就是遍历B树,而seek是B树查找直接定位。
Index scan多半是出现在索引列在表达式中。数据库引擎无 法直接确定你要的列的值,所以只能扫描整个整个索引进行计算。index seek就要好很多.数据库引擎只需要扫描几个分支节点就可以定位到你要的记录。回过来,如果聚集索引的叶子节点就是记录,那么Clustered Index Scan就基本等同于full table scan。

一些优化原则
1、缺省情况下建立的索引是非聚簇索引,但有时它并不是最佳的。在非群集索引下,数据在物理上随机存放在数据页上。合理的索引设计要建立在对各种查询的分析和预测上。一般来说: 
a.有大量重复值、且经常有范围查询( > ,< ,> =,< =)和order by、group by发生的列,可考 
虑建立群集索引; 
b.经常同时存取多列,且每列都含有重复值可考虑建立组合索引; 
c.组合索引要尽量使关键查询形成索引覆盖,其前导列一定是使用最频繁的列。索引虽有助于提高性能但不是索引越多越好,恰好相反过多的索引会导致系统低效。用户在表中每加进一个索引,维护索引集合就要做相应的更新工作。 

2、ORDER BY和GROPU BY使用ORDER BY和GROUP BY短语,任何一种索引都有助于SELECT的性能提高。 

3、多表操作在被实际执行前,查询优化器会根据连接条件,列出几组可能的连接方案并从中找出系统开销最小的最佳方案。连接条件要充份考虑带有索引的表、行数多的表;内外表的选择可由公式:外层表中的匹配行数*内层表中每一次查找的次数确定,乘积最小为最佳方案。

4、任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。 

5、IN、OR子句常会使用工作表,使索引失效。如果不产生大量重复值,可以考虑把子句拆开。拆开的子句中应该包含索引。
Sql的优化原则2: 
1、只要能满足你的需求,应尽可能使用更小的数据类型:例如使用MEDIUMINT代替INT 
2、尽量把所有的列设置为NOT NULL,如果你要保存NULL,手动去设置它,而不是把它设为默认值。 
3、尽量少用VARCHAR、TEXT、BLOB类型 
4、如果你的数据只有你所知的少量的几个。最好使用ENUM类型  

使用SQLServer Profiler找出数据库中性能最差的SQL
首先打开SQLServer Profiler:

 


然后点击工具栏“New Trace”,使用默认的模板,点击RUN。

也许会有报错:"only TrueType fonts are supported. There id not a TrueType font"。不用怕,点击Tools菜单->Options,重新选择一个字体例如Vendana 即可。(这个是微软的一个bug)

运行起来以后,SQLServer Profiler会监控数据库的活动,所以最好在你需要监控的数据库上多做些操作。等觉得差不多了,点击停止。然后保存trace结果到文件或者table。
这里保存到Table:在菜单“File”-“Save as ”-“Trace table”,例如输入一个master数据库的新的table名:profileTrace,保存即可。

找到最耗时的SQL:
  1. use master
  2. select * from profiletrace order by duration desc;
复制代码
找到了性能瓶颈,接下来就可以有针对性的一个个进行调优了。

对使用SQLServer Profiler的更多信息可以参考:
http://www.codeproject.com/KB/database/DiagnoseProblemsSQLServer.aspx

使用SQLServer Database Engine Tuning Advisor数据库引擎优化顾问
使用上述的SQLServer Profiler得到了trace还有一个好处就是可以用到这个优化顾问。用它可以偷点懒,得到SQLServer给您的优化顾问,例如这个表需要加个索引什么的…
首先打开数据库引擎优化顾问:
 

然后打开刚才profiler的结果(我们存到了master数据库的profileTrace表):

 

点击“start analysis”,运行完成后查看优化建议(图中最后是建议建立的索引,性能提升72%)

 
这个方法可以偷点懒,得到SQLServer给您的优化顾问。
 
原文地址:http://blog.chinaunix.net/uid-116213-id-3395051.html
分享到:
评论

相关推荐

    MySQL 聚簇索引.rar

    在MySQL中,索引分为两种主要类型:聚簇索引(Clustered Index)和非聚簇索引(Secondary Index或Non-Clustered Index)。聚簇索引决定了数据行在磁盘上的物理存储方式,而非聚簇索引则不直接决定数据行的位置,而是...

    一篇文章讲清楚MySQL的聚簇-联合-覆盖索引、回表、索引下推.doc

    非聚簇索引(Non-Clustered Index)与聚簇索引不同,它的叶子节点中只存储了当前索引字段和主键 ID。假设我们在 age 字段上建一个普通索引,age 字段上面的索引存储结构就是非聚簇索引。 联合索引(Composite Index...

    行业-69 更新数据的时候,自动维护的聚簇索引到底是什么?l.rar

    与聚簇索引相对的是非聚簇索引(Non-Clustered Index),非聚簇索引并不影响数据的物理存储顺序,它只是一个指向实际数据行的指针列表。一个表可以有多个非聚簇索引,但每次查询时,非聚簇索引需要通过索引找到对应...

    关于数据库中的索引原理

    根据索引的数据存储方式不同,索引可以分为两大类:聚簇索引(Clustered Index)和非聚簇索引(Non-Clustered Index)。 - **聚簇索引**:聚簇索引决定了表中行的实际物理顺序。一个表只能有一个聚簇索引。 - **非...

    Sybase索引的使用和优化

    二、非聚簇索引(Non-Clustered Indexes) 非聚簇索引是指除了聚簇索引以外的其他类型的索引。非聚簇索引不重新组织表中的数据,而是对每一行存储索引列值并用一个指针指向数据所在的页面。换句话说非聚簇索引具有...

    SQLServer索引调优实践

    - **非聚簇索引(Non-Clustered Index)**:数据行的物理顺序与索引的逻辑顺序不同。非聚簇索引包含指向数据行的实际位置的指针。 以新华字典为例,当你查找“爬”字时,可以直接翻到P开头的部分,这就是聚簇索引的...

    Sybase SQL Server索引的使用和优化.pdf

    二、非聚簇索引(Non-Clustered Indexes) 非聚簇索引是SQL Server缺省情况下建立的索引。非聚簇索引不重新组织表中的数据,而是对每一行存储索引列值并用一个指针指向数据所在的页面。非聚簇索引具有在索引结构和...

    mysql索引和锁机制ppt介绍

    **非聚簇索引(Non-Clustered Index):** - 非聚簇索引的索引顺序与数据的物理排列顺序无关。 - 叶子节点包含了指向实际数据行的指针(或称为书签),而不是实际的数据行。 - 例子:查找字典中的某个字时,先查目录...

    MySQL技术之索引.pptx

    - **非聚簇索引 (Non-Clustered Index / Secondary Index)**:也称为二级索引,其叶子节点存储的是主键值而不是行的物理位置。在InnoDB中,非主键的索引被称为辅助索引。 - **辅助索引**:是最基础的索引类型,对...

    数据库索引

    根据索引的存储方式及其在数据库中的作用不同,索引主要可以分为两大类:聚簇索引(Clustered Index)和非聚簇索引(Non-Clustered Index)。 **聚簇索引:** - 特点:数据按索引的顺序存储。 - 用途:提高多行检索...

    MySQL高级篇-索引(Index)的数据结构

    2. 非唯一索引(Non-Unique Index):允许索引列中有重复的值。 六、覆盖索引(Covering Index) 如果一个查询可以从索引中获取所有需要的数据,而无需回表查询数据行,那么这个索引就被称为覆盖索引。覆盖索引可以...

    聚集索引和非聚集索引的区别

    相比之下,非聚集索引(Non-Clustered Index)并不影响数据的物理存储顺序。非聚集索引拥有自己的独立结构,其叶子节点通常包含键值以及指向实际数据行的书签或指针。这意味着,查询非聚集索引时,数据库系统需要两...

    实验九-视图和索引及数据关系图.doc

    索引可以是唯一的(UNIQUE)或非唯一的(NON-UNIQUE),也可以是聚簇索引(CLUSTERED)或非聚簇索引(NON-CLUSTERED)。 在SQL Server中,可以使用CREATE INDEX语句来创建索引,例如: ```sql CREATE INDEX index_...

    SQLServer聚集索引与非聚集索引讲解[借鉴].pdf

    聚集索引(Clustered Index)和非聚集索引(Non-Clustered Index)是SQL Server中两种不同的索引类型,了解它们的区别和应用场景对于提高数据库性能和查询效率至关重要。 一、索引结构 索引是一种特殊的目录,用于...

    聚集索引与非聚集索引的区别

    在数据库领域,索引分为两大类:**聚焦索引(Clustered Index)**和**非聚焦索引(Non-clustered Index)**。 #### 二、聚焦索引详解 聚焦索引是一种特殊类型的索引,其键值的逻辑顺序直接决定了表中数据行的物理顺序...

    Mysql-索引原理分析

    非聚集索引(Secondary Index,或Non-Clustered Index)与聚集索引不同,它的索引结构独立于数据行。非聚集索引中,每个索引条目包含键值和一个书签,书签指向对应数据行的实际位置。这意味着,对于非聚集索引查询,...

    MYSQL专题-查询优化-使用索引-安全隐患-事务与锁.docx

    索引可以分为Clustered Index和Non-Clustered Index 两种,Clustered Index 是对整个表的索引,而 Non-Clustered Index 是对某个列的索引。 七、安全隐患 数据库安全隐患是一个非常重要的问题,需要防止 SQL 注入...

    Java大厂面试专题课-MySQL面试题-参考回答

    - 非聚簇索引(Non-clustered Index)则是将数据与其索引分开存储,索引节点中只包含指向实际数据行的指针。这种索引适用于辅助键和其他查询条件。 #### 回表查询 - **面试官提问**: 什么是回表查询? - **解答**...

    V1.0-sqlServer索引使用总结.docx

    2. 非聚合索引(Non-Clustered Index):非聚合索引不包含实际的数据,而是将索引的键值和指向实际数据的指针组合在一起。非聚合索引可以提高查询速度,但它不会增加插入、更新和删除操作的时间。 索引的使用方法 ...

Global site tag (gtag.js) - Google Analytics