日期:2014-05-16  浏览次数:21843 次

Oracle数据库的SQL性能问题分析

在Oracle 10.2.0.4数据库中,有一个SQL执行缓慢,超过数分钟无结果,等待事件又是空闲的SQL*Net message事件,最后只好强行中断。
这个SQL是一个普通的UPDATE语句,where子句中多张表关联,关联的表都是临时表。

update t_fund_product_info
     set is_valid = 'N'
   where prdt_id not in
         (select a.prdt_id
            from tmp_crm_DX_PRDT_FOR_INFO a, tmp_crm_PRDT_CATA_FOR_INFO b
           where a.prdt_type = '501040'
             and a.prdt_id = b.prdt_id
             and b.prdt_key in (select distinct prdt_id
                                  from tmp_crm_PRDT_CHANNEL
                                 where dg_ch = 'XX商城'));

?
这个SQL语句,多次执行都没有出来结果。

在PL SQL DEV中F5得到的执行计划是这样:

UPDATE STATEMENT, GOAL = ALL_ROWS       
 UPDATE    SCOTT    T_FUND_PRODUCT_INFO
  FILTER       
   TABLE ACCESS FULL    SCOTT    T_FUND_PRODUCT_INFO
   NESTED LOOPS       
    NESTED LOOPS       
     TABLE ACCESS FULL    SCOTT    TMP_CRM_DX_PRDT_FOR_INFO
     TABLE ACCESS FULL    SCOTT    TMP_CRM_PRDT_CATA_FOR_INFO
    TABLE ACCESS FULL    SCOTT    TMP_CRM_PRDT_CHANNEL

?
虽然都是全表扫描,但表也不大,都是几千条记录。 NESTED LOOPS??? (嵌套连接)也没有什么问题。

?

(miki西游 @mikixiyou 原文链接: http://mikixiyou.iteye.com/blog/1755048 )


我在表t_fund_product_info的字段prdt_id上建立主键,执行就OK。得到的执行计划是这样:

UPDATE STATEMENT, GOAL = ALL_ROWS       
 UPDATE    SCOTT    T_FUND_PRODUCT_INFO
  HASH JOIN RIGHT ANTI       
   VIEW    SYS    VW_NSO_1
    HASH JOIN       
     HASH JOIN       
      TABLE ACCESS FULL    SCOTT    TMP_CRM_PRDT_CHANNEL
      TABLE ACCESS FULL    SCOTT    TMP_CRM_PRDT_CATA_FOR_INFO
     TABLE ACCESS FULL    SCOTT    TMP_CRM_DX_PRDT_FOR_INFO
   TABLE ACCESS FULL    SCOTT    T_FUND_PRODUCT_INFO

?
这个执行符合我的要求,是HASH JOIN RIGHT ANTI(哈希反连接)。
这个库新建的,表刚刚新建。检查user_tables,确认所有的表都没有被分析过。插一句,数据库的配置没有问题。于是,手工分析一下这四张表。

       TABLE_NAME    NUM_ROWS    BLOCKS    LAST_ANALYZED
1    TMP_CRM_DX_PRDT_FOR_INFO    3624    103    2012-12-27 14:33:22
2    TMP_CRM_PRDT_CATA_FOR_INFO    2149    20    2012-12-27 14:05:02
3    TMP_CRM_PRDT_CHANNEL    6695    58    2012-12-27 14:05:02
4    T_FUND_PRODUCT_INFO    875    13    2012-12-27 14:05:02

?
再将主键删除,使用alter session set events='10046 trace name context forever,level 12'分析,得到执行计划没变化。如下:

Rows     Row Source Operation
-------  ---------------------------------------------------
      0  UPDATE  T_FUND_PRODUCT_INFO (cr=81443 pr=0 pw=0 time=455192 us)
      0   FILTER  (cr=81443 pr=0 pw=0 time=455183 us)
    875    TABLE ACCESS FULL T_FUND_PRODUCT_INFO (cr=15 pr=0 pw=0 time=903 us)
    875    NESTED LOOPS  (cr=81428 pr=0 pw=0 time=451275 us)
    916     NESTED LOOPS  (cr=57242 pr=0 pw=0 time=277376 us)
    875      TABLE ACCESS FULL TMP_CRM_DX_PRDT_FOR_INFO (cr=46157 pr=0 pw=0 time=201112 us)
    916      TABLE ACCESS FULL TMP_CRM_PRDT_CATA_FOR_INFO (cr=11085 pr=0 pw=0 time=74469 us)
    875     TABLE ACCESS FULL TMP_CRM_PRDT_CHANNEL (cr=24186 pr=0 pw=0 time=172016 us)

?
这个执行很快结束,并且成功。
再将主键恢复,继续alter session set events='10046 trace name context forever,level 12'分析执行,得到执行计划如下:

Rows     Row Source Operation
-------  ---------------------------------------------------
      0  UPDATE  T_FUND_PRODUCT_INFO (cr=207 pr=0 pw=0 time=10225 us)
      0   HASH JOIN ANTI (cr=207 pr=0 pw=0 time=10223 us)
    875    TABLE ACCESS FULL T_FUND_PRODUCT_INFO (cr=16 pr=0 pw=0 time=7102 us)
    912    VIEW  VW_NSO_1 (cr=191 pr=0 pw=0 time=7175 us)
    912     HASH JOIN  (cr=191 pr=0 pw=0 time=6260 us)
   1351      HASH JOIN  (cr=130 pr=0 pw=0 time=4500 us)
   1595       TABLE ACCESS FULL TMP_CRM_DX_PRDT_FOR_INFO (cr=107 pr=0 pw=0 time=28 us)
   2149       TABLE ACCESS FULL TMP_CRM_PRDT_CATA_FOR_INFO (cr=23 pr=0 pw=0 time=21 us)
   1032      TABLE ACCESS FULL TMP_CRM_PRDT_CHANNEL (cr=61 pr=0 pw=0 time=30 us)

?