的同时,也会在物理上让数据尽可能地排序。在索引子叶层级中的每个数据页都有一个指针指向索引分页的前一页与后一页,形成双向链接串行,在内部的
系统数据表包含了各索引子叶层第一个分页的地址,为了保证数据在逻辑上是依照聚集索引的顺序存放的,SQL SERVER 只需要由第一个分页开始,并依照其连接串行一个接着一个依序寻找数据即可。如下图。
SQL Server查询性能优化――创建索引原则(一)(二)
注:聚集表是有聚集索引的表。
非聚集索引
非聚集索引是完全独立于数据表之外的结构,所以不会影响数据行的顺序,其子叶层包含索引行。每个索引行包含非聚集键值、行定位符和任意包含列或非键列。行定位符中存入的数据有两种类型:书签(BOOKMARK)或聚集索引的键值。如果数据表上建立了聚集索引,则行定位符中存入的数据就是聚集索引的键值。如果数据表没有建立聚集索引,则行定位符中存入的数据就是书签,即指向数据表中记录具体位置的ROWID,也就是文档编号、分页编号与页内记录编号(称之为SOLT编号)所组合成的值。通过该ROWID 在数据表内获取数据就称为书签查找 BOOKMARK LOOKUP。所以,一般通过非聚集索引查找到符合的键值后,还会搭配书签查找。
当非聚集索引从结构中找到符合的记录时,虽然在子叶层该键值是由小到大排序,因此可能在一个分页上就有全部符合查询条件的键值,但因为数据表中数据行的摆放是没有按顺序的(或是说没有按照该非聚集索引的键值顺序摆放),所以真正符合记录的数据是散布在文档各处的,而SQL SERVER每次读取数据都是以数据页为单位,因此,找到一条记录所在位置后,要先将存放该条记录的分页读到内存中,再从该页读出记录。
因为BOOKMARK LOOKUP是进行随机的I/O操作,当符合查询的记录很多时,通过非聚集索引访问将导致数据页读取非常频繁,就算两条记录在同一个分页,该分页也会被重复读两次,因此或符合的记录有N条,就需要读取数据表内的分页N页,虽然大部分的读取操作都是针对内存中的高速缓存,但记录数过多时一样没有效率,还不如数据表扫描,全部扫描一遍,把符合条件数据找出来。
虽然 SQL 2005 以后的版本中已经不在提 BOOKMARK LOOKUP了(但实际上却是换汤不换药),我们的很多搜索都是使用如下的搜索过程:先在非聚集中找,然后再在聚集索引中找。如下图。
非聚集索引 ( Unclustered Index)
·非聚集索引的页,不是数据,而是指向数据页的页。
·若未指定索引类型,则默认为非聚集索引
·叶节点页的次序和表的物理存储次序不同
·每个表最多可以有 249个非聚集索引(一般认为每个表不应该超过10个索引)
·在非聚集索引创建之前创建聚集索引(否则会引发索引重建)
聚集索引与非聚集索引使用的情况:
动作描述
使用聚集索引
使用非聚集索引
外键列
应
应
主键列
应
应
列经常被分组排序(order by)
应
应
返回某范围内的数据
应
不应
小数目的不同值
应
不应
大数目的不同值
不应
应
频繁更新的列
不应
应
频繁修改索引列
不应
应
一个或极少不同值
不应
不应
今天就普及一下索引的一些基本知识,明天来说明怎么选择要创建索引的列,条件是什么,方法是什么。