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

      今天在监控数据库时,发现一个语句的执行时间比较长,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的效率。

   有时:聚集索引效率>索引覆盖,具体要看情况,这只是其中的一个例子。

你可能感兴趣的:(SQL Server)