您的位置:首页 > 数据库

SQL Server 优化--合理使用聚集索引

2008-10-04 15:35 399 查看
今天在监控数据库时,发现一个语句的执行时间比较长,IO次数也比较多。语句如下:

select * from Docbase this_ where

id in ( select objid from Categorylink categorylink where

categorylink.objtype='Docbase' and (categorylink.categoryid =

'4028827015a82d020115d07b6b604689')) and pid is null and isdelete=0 and

exists(select 'X' from Permissiondetail p where p.objid=this_.id and

p.objtable='docbase'and p.userid in('','ISALLUSER','402882ed0eb78aae010ec124f7fe5c87',

'402881a10d33db44010d3402fc2b00c3') and 10 between p.minseclevel and p.maxseclevel and p.opttype > 2 ) and not exists (select 'X' from Delobj del where del.objid=this_.id and del.objtable='Docbase')
由于表Permissiondetail表数据有很多,大约有几百万条数据,先前建立一个索引来达到索引覆盖,避免表扫描。

CREATE INDEX [IX_PERMISSIONDETAIL_mu] ON [dbo].[permissiondetail]

(

[objid] ASC,[objtable]ASC,[userid] ASC,[minseclevel] ASC,[maxseclevel] ASC,[opttype] ASC

)

执行结果如下:

(495 行受影响)

表 'delobj'。扫描计数 1,逻辑读取 2 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

表 'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

表 'docbase'。扫描计数 1,逻辑读取 659 次,物理读取 0 次,预读 0 次,lob 逻辑读取 85 次,lob 物理读取 0 次,lob 预读 0 次。

表 'categorylink'。扫描计数 3,逻辑读取 36 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

表 'Permissiondetailworkflowbase'。扫描计数 1,逻辑读取 30690 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

后来发现这样的优化效果也是不明细,因为这里运行的速度也不是很快,因为数据库是Index scan,他会对索引的全部数据进行扫描。一旦数据量大,也很慢,而且这个索引的长度太长了,影响DML语句。后来通过分析表的数据分布。和userid的数据情况,在userid里建立一个聚集索引,效率会大于索引覆盖。

CREATE clustered INDEX [IX_PERMISSIONDETAIL_userid] ON [dbo].[permissiondetail] ( [userid] ASC)
执行语句结果:

(495 行受影响)

表 'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

表 'Permissiondetail'。扫描计数 1988,逻辑读取 10106 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

表 'docbase'。扫描计数 1,逻辑读取 659 次,物理读取 0 次,预读 0 次,lob 逻辑读取 87 次,lob 物理读取 0 次,lob 预读 0 次。

表 'categorylink'。扫描计数 1,逻辑读取 12 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

表 'delobj'。扫描计数 1,逻辑读取 2 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
结果:是IO次数比先前提高了3倍,而且DML的影响是比较少的。

总结:

这个案例有个特殊性,就是对Permissiondetail大表会有查询很多的数据,这时如果不能达到索引覆盖,执行的时间比较长,但是这样的做饭牺牲了很多其他的性能:插入,更新和删除数据,不是最优的。我们更改了索引,将userid改成聚集索引,一样达到了提高效率的方法,同时也提高了DML的效率。

有时:聚集索引效率>索引覆盖,具体要看情况,这只是其中的一个例子。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: