Oracle - 可以采取哪些措施来删除Full Table Scan / Table Access Full?

时间:2017-06-09 20:37:31

标签: sql oracle oracle10g sqlperformance

需要调优的Oracle SQL:

SELECT mcei.mcei_sid
FROM MA_CE mc
JOIN MA_CE_EN mce
ON mc.mc_id=mce.mc_cd
JOIN MA_CE_EN_IN mcei
ON mce.mce_sid                =mcei.mce_sid
WHERE mc.active_flag          = 'Y'
AND mce.active_flag           = 'Y'
AND Mcei.Latest_Full_Run_Flag = 'Y'
AND Mcei.Engine_Type_Cg_Sid   = GE_CG_SI_FR_C_SN ('MEI_ENGTYPE','COB')
AND Mcei.Mcei_State_Cg_Sid    = GE_CG_SI_FR_C_SN ('MCEI_STATE','COMPLETED')
AND Mc.Mc_Id         = NVL(6,Mc.Mc_Id)
AND mcei.business_dt = NVL(NULL -- this is a parameter which could be NULL or a Date       
  ,
  (SELECT mcei.business_dt
  FROM MA_CE_EN e
  WHERE e.current_cob_mei_sid  =mcei.mcei_sid
  AND e.active_flag            ='Y'
  AND mcei.Latest_Full_Run_Flag='Y'
  AND e.mce_sid                =mce.mce_sid
  ));

解释计划:

----------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name                          | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                               |     1 |    40 |   825   (2)| 00:00:10 |
|*  1 |  FILTER                        |                               |       |       |            |          |
|*  2 |   HASH JOIN                    |                               |   376 | 15040 |   636   (3)| 00:00:08 |
|   3 |    NESTED LOOPS                |                               |     1 |    14 |     4   (0)| 00:00:01 |
|*  4 |     TABLE ACCESS BY INDEX ROWID| MA_CE                         |     1 |     5 |     1   (0)| 00:00:01 |
|*  5 |      INDEX UNIQUE SCAN         | IPK_MA_CE                     |     1 |       |     0   (0)| 00:00:01 |
|*  6 |     TABLE ACCESS FULL          | MA_CE_EN                      |     1 |     9 |     3   (0)| 00:00:01 |
|*  7 |    TABLE ACCESS FULL           | MA_CE_EN_IN                   |  4817 |   122K|   632   (3)| 00:00:08 |
|*  8 |   FILTER                       |                               |       |       |            |          |
|*  9 |    TABLE ACCESS BY INDEX ROWID | MA_CE_EN                      |     1 |    11 |     1   (0)| 00:00:01 |
|* 10 |     INDEX UNIQUE SCAN          | IPK_MCENG                     |     1 |       |     0   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------------

谓词信息(由操作ID标识):

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

   1 - filter("MCEI"."BUSINESS_DT"= (SELECT :B1 FROM "MA_CE_EN" "E" WHERE :B2='Y' AND 
              "E"."MCE_SID"=:B3 AND "E"."CURRENT_COB_MEI_SID"=:B4 AND "E"."ACTIVE_FLAG"='Y'))
   2 - access("MCE"."MCE_SID"="MCEI"."MCE_SID")
   4 - filter("MC"."ACTIVE_FLAG"='Y')
   5 - access("MC"."MC_ID"=6)
   6 - filter("MCE"."ACTIVE_FLAG"='Y' AND "MC"."MC_ID"="MCE"."MC_CD")
   7 - filter("MCEI"."LATEST_FULL_RUN_FLAG"='Y' AND 
              "MCEI"."MCEI_STATE_CG_SID"="GE_CG_SI_FR_C_SN"('MCEI_STATE','COMPLETED') AND 
              "MCEI"."ENGINE_TYPE_CG_SID"="GE_CG_SI_FR_C_SN"('MEI_ENGTYPE','COB'))
   8 - filter(:B1='Y')
   9 - filter("E"."CURRENT_COB_MEI_SID"=:B1 AND "E"."ACTIVE_FLAG"='Y')
  10 - access("E"."MCE_SID"=:B1)

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

否。查询中使用的3个表中的行数:

    ma_ce - 10  
    ma_ce_en - 10   
    ma_ce_en_in - 160000

(ma_ce_en_in表是罪魁祸首。列MCEI_SID和MCEI_SID_SEQ上的主键。此表中没有其他索引。)

问题1 - 我想调整查询,因此我不想在ma_ce_en_in上进行全表扫描(或表访问已满),因为这是唯一的大表。如何从此表中删除全表扫描?

问题2 - 上述查询存在于函数中,如何查找函数在一周内运行的次数?

2 个答案:

答案 0 :(得分:0)

在其中一条评论中,低于帖子(而不是在应该的位置),你声明你有一个关于LATEST_FULL_RUN_FLAG,MCEI_STATE_CG_SID和ENGINE_TYPE_CG_SID的索引。

将FLAG设置为' Y' (您可以运行一个简单的查询来查找。)如果答案是"行的一半"甚至" 15%的行",优化器可能会选择不使用索引。 (如果只有1%的行将标志设置为' Y'那么应该使用索引。)

如果是这样的话 - STATE_CG_SID或ENGINE_TYPE_CG_SID是否更具选择性?例如,每个可能的值出现在不超过1%的行中?如果是这样,您应该将多选列的列FIRST放在多列索引中;优化程序可以使用索引的唯一方法是索引中FIRST列的值是非常有选择性的。否则,您将最终进行全表扫描。

答案 1 :(得分:0)

问题2 - 上述查询存在于函数中,如何查找函数在一周内运行的次数?

答案 - 你找不到。功能执行的次数。但是你可以找到它的sql被执行了多少次。

<强> A) 找不到。执行,你可以检查AWR,但有可能你的sql没有被awr拿起。 您可以在下面执行以获取awr中所有sql的统计信息。

begin
    dbms_workload_repository.modify_snapshot_settings (topnsql=>'MAXIMUM');
end;

<强> b)中 但是,您可能无法将上述代码运行到prod中。所以下一个选择是检查oracle视图。

  1. 从文本中找到SQL_ID

    从v $ sql v中选择执行,v。*其中sql_text喜欢&#39;%select * from ABCtable%&#39;; - 90771ja3rt3rw

  2. select executions_delta-- "Executions" from dba_hist_sqlstat t, dba_hist_snapshot s where t.snap_id = s.snap_id and t.dbid = s.dbid and t.instance_number = s.instance_number and sql_id='90771ja3rt3rw' -- and to_char(BEGIN_INTERVAL_TIME, 'yyyy-mm-dd') = '2017-05-15' ;