从Clustering Factor说起

 

引用的链接:http://www.cnblogs.com/killkill/archive/2009/10/04/1578054.html

 

这篇文章从Oracle 的Clustering Factor说起,尝试比较了ORACLE与SQL Server两个数据库,一开始作者认为这2个数据库在这方面应该差不多,但实际最后发现在一个数据库上的概念,在另一个数据库上不一定有;在一种数据库上有的问题,在另一种数据库上根本就没有这个问题。

 

但是我觉得这里作者的结论是不正确的。作者说Clustering Factor反映了ORACLE数据库中数据存储的杂乱程度,如果值越大,说明存储的数据越杂乱无章,这个杂乱无章是指对通过索引来访问数据时,索引记录散射到了大量的数据页面,而不是散射到了集中的少量的数据页上。

 

我认为SQL Server也是这样的,SQL Server虽然没有Clustering Factor这个参数,但问题是一样的。

比如建了一个索引,而这个索引中存放在同一页中的索引记录对应的索引值所在的数据记录的页面,如果是很离散的,比如,索引中有一个叶级页,存放了100条索引记录,也就是对应了100条数据记录,那么这100条记录,有可能存放在100个数据页上,这并不是说在SQL Server上存储的数据很杂乱,而是从索引记录到数据记录的对应关系很杂乱,不是说N条索引记录都在一个或者少数几个数据页面上,而是分布在很大范围的数据页上,那么读取同样多的数据,可能需要读取更多次,而很多读到的记录都不是我们需要的,都不是查询范围内的数据,这是因为你要读取一条记录,那么需要读取包含这条记录的整个数据页。

在oracle中创建表的语句:

create table tab02 as select * from source order by y;

 

在SQL Server中创建表的语句:

select * into tab02 from Source order by x;

 

需要特别指出的是,在SQL Server的帮助文件中写了:在与 SELECT...INTO 语句一起使用以从另一来源插入行时,ORDER BY 子句不能保证按指定的顺序插入这些行。

也就是说作者以为通过排序,最后tab02表中的数据是完全按照y字段的值来排序,但实际上SQL Server并不保证按指定的顺序插入这些行,甚至当这些行插入tab02时,顺序很有可能和tab01是完全一样的。

下面做一个试验,通过增加一个字段z,按z字段对tab02表建了聚集索引,来改变数据的存放顺序,也就是tab02不再按照x字段的顺序,而是按照z的值来排序,也就是创造了一个从索引记录到数据记录的杂乱的对应关系。

create table Source 
(
 x int ,
 y int,
 z int 
);

begin tran;
	declare @n int;
	
	set @n = 0;
	while @n < 1000000
	
	begin 
		insert into source(x,y,z) values ( @n , checksum(newid()),checksum(newid()) );
		set @n=@n+1;
	end;
commit;

select * into tab01 from Source;
select * into tab02 from Source order by x;

create index idx01 on tab01(x); 


--这个聚集索引保证了数据是按照z这个字段来排序存放的
create clustered index idx_tab02 on tab02(z)

create index idx02 on tab02(x); 


set statistics io on

/*
引用索引idx01,是按照x字段排序,而数据本身也是按照x字段的值来排序,
这样通过索引查找到的索引记录对应的rid,也都集中在少数数据页上,比如放在10个页上,那么访问效率肯定高

输出:
	(1 行受影响)
	表 'tab01'。扫描计数 1,逻辑读取 1007 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

	(1 行受影响)
*/
select avg(y/(x+1)) from tab01 where x between 10000 and 11000;


/*
引用索引idx02,这个索引按照x字段来排序,但数据是按照z字段存放的,
当通过索引查找到>=10000同时<=11000的1000条索引记录,索引记录中包含了数据记录的键,
通过这个键访问聚集索引中的记录,从中取出y字段,进行计算。

那么这个时候就会有问题,满足>=10000同时<=11000的索引记录一共有1000条左右,
但这1000条记录可能分布很不均匀,可能出现某条记录在第100页上,而另一条在108页上,可能这1000条记录分布在100个页上,
那么需要访问的页数也就越多。

输出:
	(1 行受影响)
	表 'tab02'。扫描计数 1,逻辑读取 3080 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

	(1 行受影响)
*/
select avg(y/(x+1)) from tab02 where x between 10000 and 11000;


原文地址:https://www.cnblogs.com/momogua/p/8304589.html