您的位置:首页 > 数据库

数据库性能优化:数据库表优化之SQL索引

2015-05-15 10:15 274 查看

一、什么是索引

       SQL索引有两种,聚集索引非聚集索引,索引主要目的是提高了SQL Server系统的性能,加快数据的查询速度与减少系统的响应时间。

下面举两个简单的例子:

      图书馆的例子:一个图书馆那么多书,怎么管理呢?

建立一个字母开头的目录,例如:a开头的书,在第一排,b开头的在第二排,这样在找什么书就好说了,这个就是一个聚集索引,

可是很多人借书找某某作者的,不知道书名怎么办?图书管理员在写一个目录,某某作者的书分别在第几排,第几排,这就是一个非聚集索引

     字典的例子:字典前面的目录,可以按照拼音和部首去查询,

我们想查询一个字,只需要根据拼音或者部首去查询,就可以快速的定位到这个汉字了,这个就是索引的好处,拼音查询法就是聚集索引,部首查询就是一个非聚集索引.

 

 

二、索引的存储机制

      首先,无索引的表,查询时,是按照顺序存续的方法扫描每个记录来查找符合条件的记录,这样效率十分低下,举个例子,如果我们将字典的汉字随即打乱,没有前面的按照拼音或者部首查询,那么我们想找一个字,按照顺序的方式去一页页的找,这样效率有多底,大家可以想象。

       聚集索引和非聚集索引的根本区别是表记录的排列顺序和与索引的排列顺序是否一致,其实理解起来非常简单,还是举字典的例子:如果按照拼音查询,那么都是从a-z的,是具有连续性的,a后面就是b,b后面就是c, 聚集索引就是这样的,他是和表的物理排列顺序是一样的,例如有id为聚集索引,那么1后面肯定是2,2后面肯定是3,所以说这样的搜索顺序的就是聚集索引。非聚集索引就和按照部首查询是一样是,可能按照偏房查询的时候,根据偏旁‘弓’字旁,索引出两个汉字,张和弘,但是这两个其实一个在100页,一个在1000页,(这里只是举个例子),他们的索引顺序和数据库表的排列顺序是不一样的,这个样的就是非聚集索引。

      原理明白了,那他们是怎么存储的呢?在这里简单的说一下,聚集索引就是在数据库被开辟一个物理空间存放他的排列的值,例如1-100,所以当插入数据时,他会重新排列整个整个物理空间,而非聚集索引其实可以看作是一个含有聚集索引的表,他只仅包含原表中非聚集索引的列和指向实际物理表的指针。他只记录一个指针,其实就有点和堆栈差不多的感觉了

          只需要在数据表的一个字段上建立聚集索引就可以了,而究竟要在哪一个字段上建立聚集索引大家一定好好斟酌,本人建议那一个字段在order by中经常要排序的

因为数据页都已经按照聚集索引的第一个字段排好序的了而不像非聚集索引的索引页跟数据表的记录一一对应,扫描的时候扫描索引页的每一行。非聚集索引的使用和聚集索引使用方式也差不多,就是在经常作为查询条件的字段上做索引

三、创建索引

聚集索引

CREATE  CLUSTERED INDEX 索引名

ON 表(字段)

非聚集索引

CREATE  NONCLUSTERED INDEX 索引名

ON 表名 (字段)

删除索引

Drop Index 表名.索引名

            查看索引

           sp_helpIndex 表名

四、什么情况下设置索引

动作描述
使用聚集索引 
 使用非聚集索引
 外键列
 应
 应
 主键列
 应
 应
 列经常被分组排序(order by)
 应
 应
 返回某范围内的数据
 应
 不应
 小数目的不同值
 应
 不应
 大数目的不同值
 不应
 应
 频繁更新的列
不应 
 应
 频繁修改索引列
 不应
 应
 一个或极少不同值
 不应
 不应
 

五、使用索引优化数据库查询效率

1.不宜创建索引的情形

   (1)经常插入,修改和删除的表

   (2)数据量比较小的表,因为查询优化器在搜索索引时所花费的时间可能会大于遍历全表的数据所需要的时间

 

2.适合创建索引的情形
   (1)主键,外键一定要建立索引

   (3) 对于经常查询的数据列最好建立索引。

         select  maxValue from RecordDatas201507

   (4) 对于需要在指定范围内的快速或频繁查询的数据列; between ...and..

  (5) 经常用在WHERE子句中的数据列。

  (6) 经常出现在关键字order by、group by、distinct后面的字段,建立索引。

       如果建立的是复合索引,索引的字段顺序要和这些关键字后面的字段顺序一致,否则索引不会被使用

  (7) 对于那些查询中很少涉及的列,重复值比较多的列不要建立索引。

  (8) 对于定义为text、image和bit的数据类型的列不要建立索引。

  (9) 对于经常存取的列避免建立索引

  (10) 限制表上的索引数目。对一个存在大量更新操作的表,所建索引的数目一般不要超过3个,最多不要超过5个。索引虽说提高了访问速度,但太多索引会影响数据的更新操作。

 (11) 对复合索引,按照字段在查询条件中出现的频度建立索引。

        在复合索引中,记录首先按照第一个字段排序。对于在第一个字段上取值相同的记录,系统再按照第二个字段的取值排序,以此类推。因此只有复合索引的第一个字段出现在查询条件中,该索引才可能被使用,因此将应用频度高的字段,放置在复合索引的前面,会使系统最大可能地使用此索引,发挥索引的作用。

 

3.聚集索引的设计原则

  (1)该列的数值是唯一的或者很少有重复的记录

  (2)经常使用between ...and..按顺序查询的列

  (3)定义identity的唯一列.

  (4)经常用于对数据进行排序的列.

 

六、无法使用索引的select语句

1.对索引列使用了函数,如:

   如果一个表有两万条记录,建议不使用函数;如果一个表有五万条以上记录,严格禁止使用函数!

select * from tb where max(id)=100

 

2.对索引列使用了'%xx',如:

  select * from tb where id like '%1'

  需要注意的不是所有使用like关键字的select 语句都无法使用索引,比如

  select * from tb where id like '1%'就可以使用索引

 

3.在where子句中对列进行类型转换(其实也是使用到了函数)

 

4.在组合索引的第1列不是使用最多的列,如在下面3个查询语句中建立组合索引,按顺序包含col2,col1,id列;

  select * from tb where id='1' and col1='aa'

  select id,sum(col1) from tb group by id

  select * from tb where id='2' and col2='bb'

  则第一句和第二句无法使用到索引 所以需要注意组合索引的顺序

 

5.在where 子句中使用in关键字的某些句子

   当在in关键字后面使用嵌套的select语句,将无法使用在该列上定义的索引

如:

select

 *

from

 ta

where

 id

in

 (select id from tb where ....)

 

--这样可以用到索引

select * from tb where id in('1','2')

6、空值不在索引中存储,所以

    select field3,field4 from tb where field2 is[not] null不使用索引。

7、不等式如

    select field3,field4 from tb where field2!='TOM'不使用索引。

    相似地,

    select field3,field4 from tb where field2 not in('M','P')不使用索引。

8、  MAX,MIN等函数,如

  Select max(field2) from tb使用索引。所以,如果需要对字段取max,min,sum等,应该加索引。

  一次只使用一个聚集函数,如:

  select “min”=min(field1), “max”=max(field1)  from tb     

  不如:select “min”=(select min(field1) from tb) , “max”=(select max(field1) from tb)   

 

9、 重复值过多的索引不会被查询优化器使用。而且因为建了索引,修改该字段值时还要修改索引,所以更新该字段的操作比没有索引更慢。

 

10、 索引值过大(如在一个char(40)的字段上建索引),会造成大量的I/O开销(甚至会超过表扫描的I/O开销)。因此,尽量使用整数索引。 Sp_estspace可以计算表和索引的开销。

 

11、 对于多列索引,order by的顺序必须和索引的字段顺序一致。

 

12、 在sybase中,如果order by的字段组成一个簇索引,那么无须做order by。记录的排列顺序是与簇索引一致的。

 

 实例:

--判断RecordTable201507表中的 RecordTable201507_index索引是否存在
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[RecordTable201507]') AND name =  'RecordTable201507_index')
Begin
CREATE CLUSTERED INDEX [RecordTable201507_index] ON [dbo].[RecordTable201507]
(
[EquipmentID] ASC,
[VarID] ASC,
[Time] ASC
)WITH (PAD_INDEX  = OFF,
STATISTICS_NORECOMPUTE  = OFF,
SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF,
DROP_EXISTING = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS  = ON,
ALLOW_PAGE_LOCKS  = ON)
ON [PRIMARY]
end


 



扩展阅读:



关于SQL的执行计划/查看SQL语句的具体执行过程,工作原理 

http://blog.163.com/xiao_mege/blog/static/7294275320105411942282/


SQLSERVER聚集索引与非聚集索引的再次研究(上)

http://www.cnblogs.com/lyhabc/p/3196479.html

http://www.cnblogs.com/AK2012/tag/%E6%95%B0%E6%8D%AE%E5%BA%93%E4%BC%98%E5%8C%96/

 

 

 

 

 

 

 

 

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: