sql server 2008学习4 设计索引的建议

索引设计的建议:

一.检查where子句和连接条件列

当一个查询提交到sql server时,查询优化器尝试为查询中引用的所有表查找最佳的数据访问机制,

一下是它所进行的方式。

1.优化器识别Where子句和连接条件中包含的列、

2.接着优化器检查这些列的索引.

3.优化器通过从索引上维护的统计确定子句的选择性(也就是返回多少行),评估每个索引的有效性

4.最终,优化器根据前面几个步骤中收集的信息,评估读取所限定的行开销最低的方法.

 

下面看个例子:  Table_1表内 又 30000条数据 image

执行查询:

image

查看结果:image

逻辑读取的次数为 95次.

下面加上where  条件句, where 的列 是 含有聚集索引的.

image

结果:image

很明显, 逻辑读 次数减少了两次.

 

下面看 where 条件句,where 的列 不含有索引的:

 

image

查询的结果:

image

总结:

where 子句列 帮助 优化器选择 一个对 查询最优的索引操作. 这也使用于 两个表之间的连接条件中使用的列.

优化器 查找在 where子句 或连接条件列上的索引,如果可用,考虑使用该索引 来从表中检索行,查询优化器在执行一个查询时,

考虑where子句或连接条件列上的索引. 因此,在where子句或连接条件中 频繁使用的列上有 索引将 帮助查询优化器避免基本表的扫描.

 

注意:  当一个表中的数据总量非常小以至于可以 放入一个单独的页面(8kb)时,表扫描可能比索引查找工作 得更好,

 

二: 使用 窄索引

应该避免在索引中使用 宽数据类型 的列. 比如 字符串类型(char,varchar,nchar ,nvarchar)的列有时候可能和二进制类型一样大.

窄索引可以再8kb的索引页面中 容纳比 宽索引 更多的行,这将有一下效果:

1.减少 i/o数量 (读取更少的8kb页面)

2.使数据库缓存更有效,因为 sql server 可以缓存更少的索引页面,从而减少内存中的索引页面所需的逻辑读操作.

3.减少数据库的存储空间.

 

下面看个例子:

表a image id为主键, 所以 a有个聚集索引, 那么id列的数据类型是 int,a表有数据27行数据,

说明所有的 索引 总大小为 4*27 byte, 一个索引页面(8kb)完全可以容得下.

sys.indexes系统表 在每个数据库中保存,包含了数据库中所有索引的基本信息.

DMF  sys.dm_db_index_physical_stats 包含了关于索引上统计的更详细信息.

下面看sql语句: 

  select i.name,i.type_desc,s.page_count,s.record_count,s.index_level  from sys.indexes i
  join  sys.dm_db_index_physical_stats(DB_ID(N'test'),OBJECT_ID(N'dbo.a'),null,null,'DETAILED') as s
  on i.index_id=s.index_id where i.OBJECT_ID=OBJECT_ID(N'dbo.a')
 
获取如下 结果:
 

image

说明 索引页数 是1页, index_leval =0说明是 聚集索引.

 

下面使用宽索引 的一个例子:

b表结果如下:  name列有一个  非聚集索引,索引名字为: IX_b  由于name 的数据类型为 char(500),b内数据有23行, 说明非聚集索引占用的大小事 23*500byte,那么超出了一个页面的大小,

按照预测,name的索引将存在两个索引页面, 下面用sql语句来证实这个结论.

image

 

sql语句:

 select i.name,i.type_desc,s.page_count,s.record_count,s.index_level  from sys.indexes i
  join  sys.dm_db_index_physical_stats(DB_ID(N'test'),OBJECT_ID(N'dbo.b'),null,null,'DETAILED') as s
  on i.index_id=s.index_id where i.OBJECT_ID=OBJECT_ID(N'dbo.b')

查询结果如下:

image

果然,看到 IX_b record_count =23的 行, 它的 page_count是2 ,说明我们之前的猜想是正确的.

 

这就是宽索引的劣势.

三:检查列的唯一性.

在一个具有很小范围的可能值的列(如性别,只有,f和m)上创建索引,对性能是没有很大帮助的.

因为查询优化器不能使用索引有效的减少返回的行. 

考虑只有两个唯一值 的 性别列(F和M).当执行一个 具有使用 性别列的where子句查询时,最终从表中得打很大数量的行,导致开销很大的表,或聚集索引扫描.

结论:

所以 使用where子句中的列 具有 大量的唯一行,一限制访问的行数,是个首选的方案. 应该在 这些列上 创建索引,来帮助 查询优化器

访问小的结果集.

而且,在创建多个列上的索引时(符合索引),列的顺序是有关系的.在某些情况下,先使用最有选择性的列将使索引行的列更有效率.

可以使用下面的语句 来判断 列的选择性.

 test1 自己随意定义的表
  select count(distinct EventClass) as 不同的值,
  count(EventClass) as 多少行,
  cast(count(distinct EventClass) as decimal) as 选择性 
  
   from test1

结果如下:

image

具有最高的唯一值数量(或选择性)的列 是 where子句 或连接条件 中引用的索引的 最佳候选.

 

四:考虑索引类型

`sql server主要有两种索引,聚集索引和非聚集索引,这两种类型的索引 都为 B-树 结构。两者之间的主要区别 是

聚集索引的叶子页面 是表的数据页面,因此数据和其指针的顺序相同,这意味着 聚集索引就是该表。

 

下一篇 ,主要讲述这两种索引。

posted @ 2012-09-11 12:28  左正  阅读(236)  评论(0编辑  收藏  举报