首  页  论  坛 登  录  注  册 用户中心 风  格 论坛状态  会  员 最新贴子 灌水宝贝  搜  索 短消息 博客   社区监狱 聊天室 退出
  当前位置:  论坛首页 »  Oracle技术讨论 »  DBA日记讨论区
发新贴子 回复贴子 您是本帖第 1388个阅读者     浏览上一篇主题    刷新本主题   浏览下一篇主题
10101/1页1
 主题:DBA日记第三部 像Oracle一样思考 4月2日 索引危机(2)索引范围扫描的优化方法 [全部贴] [楼主贴] [打印] [收藏]
白鳝
客户
等级:超凡入圣
经验:82646
信用:6302
金币:122893
发贴:1234
精华:1
注册:2006-6-28
状态:离线
 (0)     (0)
版块置顶  锁定  置为精华  改变显示颜色 
白鳝的个人资料   发送短消息息给白鳝   发送电邮给白鳝   复制这个帖子   引用回复这个帖子   回复这个帖子      

 DBA日记第三部 像Oracle一样思考 4月2日 索引危机(2)索引范围扫描的优化方法

42日 索引危机(2)索引范围扫描的优化方法

昨天下午又优化了几个SQL,对于这几个SQL来说,优化后都有了明显的性能提升,不过从今天上午10点多观察到的CPU使用率来看,好像变化不大。由于排队效应的存在,简单的减法并不能完全解决问题。以前排在前面的几个SQL解决了以后,又冒出了几条新的SQL,其中一条SQL每次执行的BUFFER GET数量高达3万多:

select a.filename, b.source_id, b.source_path, b.localnet_abbr, b.file_fmt,b.is_txt_fmt, a.deal_flag       

from SCH_XXX a, BBB b 

where (a.deal_flag='W' or a.deal_flag='B') and

 a.validflag='Y' and b.pipe_id=:szPipeId and a.source_id=b.source_id

从执行计划上看:

--------------------------------------------------------------------------------

| Operation                      | PHV/Object Name     |  Rows | Bytes|   Cost |

--------------------------------------------------------------------------------

|SELECT STATEMENT                |----- 1104374539 ----|       |      |   3486 |

|HASH JOIN                       |                     |    79K|    7M|   3486 |

| TABLE ACCESS BY INDEX ROWID    |BBBBB                |     2 |   98 |      2 |

|  INDEX RANGE SCAN              |FK_SOURCE_WORKFLOW   |     1 |      |      1 |

| TABLE ACCESS FULL              |SCH_XXXXX             |     1M|   61M|   3474 |

--------------------------------------------------------------------------------

从这个执行计划上看,对SCH_XXXX的扫描是开销最大的,这张表中扫描的记录数位100万(1M)。通过SPREPSQL报告,我们看到:

                                                       

                     Statement Total      Per Execute  

                     ---------------  ---------------  

        Buffer Gets:         626,984         39,186.5  

         Disk Reads:         425,693         26,605.8  

     Rows processed:              46              2.9

     CPU Time(s/ms):              50          3,113.1

 Elapsed Time(s/ms):             988         61,779.7

              Sorts:               0               .0

        Parse Calls:              16              1.0

      Invalidations:               0

      Version count:               2

    Sharable Mem(K):              29

         Executions:              16

平均每次执行返回的记录数是2.9条,也就是说真正符合条件的记录只有区区3条左右。这和执行计划中的79K相差甚远,于是我检查了一下这张表,这张表总计有200万条记录。在这张表上,有两个过滤条件(a.deal_flag='W' or a.deal_flag='B') and  a.validflag='Y'。我首先分析了一下validflag

Select validflag,count(*) from sch_xxxx group by validflag;

发现表中的大多数记录都是validflag='Y'的记录,这个字段的选择性是很差的,于是我又检查了一下deal_flag,发现绝大多数记录都是deal_flag='Y'的,其他的记录十分少,有时候甚至是0。这是一个典型的字段倾斜的案例,凑巧的是在这个SQL种并没有使用绑定变量,于是在deal_flag上创建一个索引,并且分析一下柱状图就可以解决问题。可客户协商了一下,这张表只有200万记录,可以立即创建索引,并做表分析,于是我马上执行了下面的脚本:

CREATE INDEX SHCJ.IDX_DEALFLAG ON SHCJ.SCH_XXXX(DEAL_FLAG) ;

Exec DBMS_STATS.GATHER_TABLE_STATS(ownname=> 'SHCJ', tabname=> 'SCH_XXXX', estimate_percent=>30, method_opt=>'for all indexed columns size skewonly',cascade=>true, degree=>2);

索引创建后,再次分析了表和索引,其中表中对索引字段中倾斜的字段分析了柱状图。Method_opt也可以设为'for all columns size auto',这是10G的缺省,而9i的缺省是'for all columns size 1',也就是不分析柱状图。

上诉操作完成后,我马上最这个SQL进行了分析,发现BUFFER GET的数量从近4万减少到了10.7,这个SQL产生的物理读基本上没有了。这说明和我判断的一致,这个索引起到了很好的作用。

从上午业务高峰期的情况来看,虽然又调整了3/4SQL,不过总体的效果并没有很明显的显现。上午10-1130之间,系统CPU使用率仍然在95-100%高位,平均事务响应时间虽然有了20%左右的提升,但是感觉还是很难彻底解决问题。在STATSPACK报告中,已经找不到明显的可以通过索引调整进行优化的SQL了,如何解决CPU负荷过高的问题,好像还是没有半点眉目。这套系统的SQL开销比较平均,除了排在BUFFER GET第一位的那条SQL占了整个开销的37%外,其他的SQL占整个系统BUFFER GET的比例都不高,最多的也只是在4%左右。调整这些SQL,虽然能够取得一些效果,不过效果还是不明显。看样子如果想要走捷径,必须优化这个排名TOP 1SQL。于是我再次看了看这个SQL,这条SQL涉及到两张表,一张稍微大点的表T_PRODUCT_INFO,这张表的WHERE条件中有一个PRODUCT_TYPE=:P1 AND PRODUCT_CLASS=:P2的过滤条件,另外一张表是涨小表,大概只有20来条记录。执行计划是扫描完两张表后,结果集做HASH JOIN。在T_PRODUCT_INFO表,有一个复合索引(PRODUCT_TYPE,PRODUCT_CLASS),执行计划也是通过对这个索引做范围扫描的。从执行计划上来看,是没有问题的。我看了一下,平均每次返回结果的记录数不过60多条。而T_PRODUCT_INFO做索引范围扫描找到的记录是接近700条。T_PRODUCT_INFO表的记录数为800万,从一个800万记录的表中,扫描出700条记录,这个索引的效率还是比较高的。为什么这么一个简单的SQL会产生1500多个BUFFER GET呢?我马上联想到了CLUSTER FACTOR,于是马上查了DBA_INDEXES,果然,这个索引的CLUSTER FACTOR接近记录的数量。CLUSTER FACTOR较高,在通过索引范围扫描访问表的时候,由于每个索引键值更多的指向新数据块,因此会产生更多的物理IO,并导致BUFFER GET的数量增加。

我马上找到郭工,了解这张表的用途。经过了解,这张表是存放产品的资料的,在做售后服务的时候,会通过PRODUCT_TYPEPRODUCT_CLASS,找到符合条件的备件,并根据库存情况以及本次服务的其他限定条件,查出满足条件的备件。这张表的数据是逐步添加的,随着新的产品及其备件的出现,这张表的数据也越来越多。以前这张表只有1/200万条记录,随着这几年的积累,记录数已经接近100万了。我想了一下,这张表的记录的加入,肯定不会按照PRODUCT_TYPEPRODUCT_CLASS进行排序,因此这个索引的CLUSTER FACTOR比较大也就不足为奇了。于是我问郭工,对于这张表的访问,是不是大多数都是通过PRODUCT_TYPEPRODUCT_CLASS进行,郭工想了想,说:“是的,绝大多数访问这张表都是根据这两个字段的条件,另外一种就是根据PRODUCT_ID直接定位产品。”PRODUCT_ID是这张表的主键,既然这张表主要的访问方式只有这两种,那么我倒是想出了一个优化方案。

由于这张表记录的插入顺序没有按照PRODUCT_TYPEPRODUCT_CLASS排序,所以索引范围扫描的成本较高。如果我们能够对这张表进行重组,使之按照这两个字段排序,那么范围扫描的成本就可以得到有效的减少。采用如下的方法可以完成这个优化:

1、将原表renamet_product_info_old

2、Create table t_product_info as select *  from t_product_info old order by product_type,product_class

3、创建相关索引及约束关系

4、分析表和索引

我和郭工商量了一下能否今晚实施一下这个优化操作。郭工听我说了半天CLUSTER FACTOR,也没听明白。他说:“老白,技术的问题我就不管了,我帮你申请一下今晚停机的事情。这套系统晚上就只有一些统计报表,所以晚上19点到21点之间都是可以停库的。如果你的操作能够在2个小时内完成,停机申请就没任何问题,否则我就需要和业务部门协商了。我想了想,这张表也就几百M的大小,1个小时肯定能解决问题了。

----------------------------------------------
blog:http://blog.oraclefans.cn/baishan1
xuj@justdb.cn
http://www.justdb.cn
IP:您无权察看 2010-6-7 14:52:37
  楼主   顶端
obuntu
等级:初入江湖
经验:124
信用:20
金币:170
发贴:2
精华:0
注册:2010-1-8
状态:离线
 (0)     (0)
obuntu的个人资料   发送短消息息给obuntu   发送电邮给obuntu   复制这个帖子   引用回复这个帖子   回复这个帖子   

 回复:DBA日记第三部 像Oracle一样思考 4月2日 索引危机(2)索引范围扫描的优化方法
这是一个典型的字段倾斜的案例,凑巧的是在这个SQL种并没有使用绑定变量,于是在deal_flag上创建一个索引,并且分析一下柱状图就可以解决问题。可客户协商了一下,这张表只有200万记录,可以立即创建索引,并做表分析,于是我马上执行了下面的脚本:


>>>>>>>
在这个SQL种  ---------在这个SQL中;
>>>>>>>
可客户协商了一下 ----- 和客户协商了一下。。

对错别字比较敏感。。。老白莫怪。。

CLUSTER FACTOR 是哪里看的呀?
IP:您无权察看 2010-6-8 7:43:36
  2  楼   顶端
白鳝
客户
等级:超凡入圣
经验:82646
信用:6302
金币:122893
发贴:1234
精华:1
注册:2006-6-28
状态:离线
 (0)     (0)
白鳝的个人资料   发送短消息息给白鳝   发送电邮给白鳝   复制这个帖子   引用回复这个帖子   回复这个帖子      

 回复:DBA日记第三部 像Oracle一样思考 4月2日 索引危机(2)索引范围扫描的优化方法
十分感谢,拼音输入法,经常有错别字。CLUSTER FATCOR可以从DBA_INDEXES视图中看,只要做了索引分析就有值的
----------------------------------------------
blog:http://blog.oraclefans.cn/baishan1
xuj@justdb.cn
http://www.justdb.cn
IP:您无权察看 2010-6-8 9:03:56
  3  楼   顶端
yaguo_96
等级:初入江湖
经验:148
信用:30
金币:495
发贴:4
精华:0
注册:2008-9-6
状态:离线
 (0)     (0)
yaguo_96的个人资料   发送短消息息给yaguo_96   发送电邮给yaguo_96   复制这个帖子   引用回复这个帖子   回复这个帖子   

 回复:DBA日记第三部 像Oracle一样思考 4月2日 索引危机(2)索引范围扫描的优化方法
请大侠指教。您这篇文章里说。clustering_factor增大增加了逻辑读数,因为要在块之间跳来跳去。我通过实验发现确实如此。通过增加一个字段使clustering_factor从200增加到6000,发现一个SQL的逻辑多从100升到了400.
我想问的是 如果从一个块读完一行,当下一行在同一个块的时候,这个时候不产生逻辑读了吗?
IP:您无权察看 2010-6-10 11:09:36
  4  楼   顶端
白鳝
客户
等级:超凡入圣
经验:82646
信用:6302
金币:122893
发贴:1234
精华:1
注册:2006-6-28
状态:离线
 (0)     (0)
白鳝的个人资料   发送短消息息给白鳝   发送电邮给白鳝   复制这个帖子   引用回复这个帖子   回复这个帖子      

 回复:DBA日记第三部 像Oracle一样思考 4月2日 索引危机(2)索引范围扫描的优化方法
CLUSTER FACTOR对物理读的影响更大,因为要跳来跳去读,另外如果在一个数据块中能读到多条符合条件的记录,BUFFER GET调用的数量可以减少,比如一个CALL可以找到5条记录,比一个CALL只能找到一条记录,要减少不少BUFFER GET
----------------------------------------------
blog:http://blog.oraclefans.cn/baishan1
xuj@justdb.cn
http://www.justdb.cn
IP:您无权察看 2010-6-10 13:28:23
  5  楼   顶端
yaguo_96
等级:初入江湖
经验:148
信用:30
金币:495
发贴:4
精华:0
注册:2008-9-6
状态:离线
 (0)     (0)
yaguo_96的个人资料   发送短消息息给yaguo_96   发送电邮给yaguo_96   复制这个帖子   引用回复这个帖子   回复这个帖子   

 回复:DBA日记第三部 像Oracle一样思考 4月2日 索引危机(2)索引范围扫描的优化方法
CLUSTER FACTOR对物理读的影响更大,因为要跳来跳去读,另外如果在一个数据块中能读到多条符合条件的记录,BUFFER GET调用的数量可以减少,比如一个CALL可以找到5条记录,比一个CALL只能找到一条记录,要减少不少BUFFER GET 

你说的没错。但是通过索引访问表,是先通过索引招到rowid ,在去读表。这只能一条一条访问吧。这时候一个call可以访问多条吗?
谢谢了。
IP:您无权察看 2010-6-10 14:07:00
  6  楼   顶端
白鳝
客户
等级:超凡入圣
经验:82646
信用:6302
金币:122893
发贴:1234
精华:1
注册:2006-6-28
状态:离线
 (0)     (0)
白鳝的个人资料   发送短消息息给白鳝   发送电邮给白鳝   复制这个帖子   引用回复这个帖子   回复这个帖子      

 回复:DBA日记第三部 像Oracle一样思考 4月2日 索引危机(2)索引范围扫描的优化方法
具体算法外人就不得而知了,不过从性能考虑,如果索引范围扫描的时候通过ROWID发现连续几条记录在同一个数据块中,在一个CALL中访问从程序设计角度是不难实现的,而且对性能提升有很大帮助。
----------------------------------------------
blog:http://blog.oraclefans.cn/baishan1
xuj@justdb.cn
http://www.justdb.cn
IP:您无权察看 2010-6-10 20:36:42
  7  楼   顶端
yaguo_96
等级:初入江湖
经验:148
信用:30
金币:495
发贴:4
精华:0
注册:2008-9-6
状态:离线
 (0)     (0)
yaguo_96的个人资料   发送短消息息给yaguo_96   发送电邮给yaguo_96   复制这个帖子   引用回复这个帖子   回复这个帖子   

 回复:DBA日记第三部 像Oracle一样思考 4月2日 索引危机(2)索引范围扫描的优化方法
受益匪浅多谢!
IP:您无权察看 2010-6-11 10:46:26
  8  楼   顶端
brucewoo
等级:初入江湖
经验:189
信用:43
金币:250
发贴:0
精华:0
注册:2009-4-23
状态:离线
 (0)     (0)
brucewoo的个人资料   发送短消息息给brucewoo   发送电邮给brucewoo   复制这个帖子   引用回复这个帖子   回复这个帖子   

 回复:DBA日记第三部 像Oracle一样思考 4月2日 索引危机(2)索引范围扫描的优化方法
学习一下.
IP:您无权察看 2010-6-12 14:48:18
  9  楼   顶端
tomzzy
等级:初入江湖
经验:173
信用:37
金币:485
发贴:1
精华:0
注册:2010-7-12
状态:离线
 (0)     (0)
tomzzy的个人资料   发送短消息息给tomzzy   发送电邮给tomzzy   复制这个帖子   引用回复这个帖子   回复这个帖子   

 回复:DBA日记第三部 像Oracle一样思考 4月2日 索引危机(2)索引范围扫描的优化方法
学习中,老白继续
IP:您无权察看 2010-7-29 16:05:01
  10  楼   顶端
10101/1页1
页面运行: 1981 毫秒

Powered by CWBBS 2.1  © 2005-2006 Cloud Web Soft
  Email:webmaster@justdb.cn