查询调优 - 建议

时间:2013-04-04 10:18:12

标签: sql oracle database-performance sql-tuning

我需要有关附加查询的建议。查询执行超过一个小时,并根据解释计划进行全表扫描。我是一个相当新的查询调优,并会提出一些建议。       首先,为什么我会获得全表扫描,即使我使用的所有列都在其上创建了索引。       其次,有没有可能我可以减少执行时间,所有访问的表都很庞大并包含数百万条记录,即便如此我还想找出一些选项。请帮助你。

查询:

select 
    distinct rtrim(a.cod_acct_no)||'|'||
    a.cod_prod||'|'||
    to_char(a.dat_acct_open,'Mon DD YYYY HH:MMAM')||'|'||
    a.cod_acct_title||'|'||
    a.cod_acct_stat||'|'||
    ltrim(to_char(a.amt_od_limit,'99999999999999999990.999999'))||'|'||
    ltrim(to_char(a.bal_book,'99999999999999999990.999999'))||'|'||
    a.flg_idd_auth||'|'||
    a.flg_mnt_status||'|'||
    rtrim(c.cod_acct_no)||'|'||
    c.cod_10||'|'||
    d.nam_branch||'|'||
    d.nam_cc_city||'|'||
    d.nam_cc_state||'|'||
    c.cod_1||'|'||
    c.cod_14||'|'||
    num_14||'|'||
    a.cod_cust||'|'||
    c.cod_last_mnt_chkrid||'|'||
    c.dat_last_mnt||'|'||
    c.ctr_updat_srlno||'|'||       
    c.cod_20||'|'||            
    c.num_16||'|'||
    c.cod_14||'|'||                
    c.num_10  ||'|'||
    a.flg_classif_reqd||'|'||

    (select g.cod_classif_plan_id||'|'||
     g.cod_classif_plan_id
     from
     ac_acct_preferences g 
     where 
     a.cod_acct_no=g.cod_acct_no AND g.FLG_MNT_STATUS = 'A' )||'|'||
    (select e.dat_cam_expiry from  flexprod_host.AC_ACCT_PLAN_CRITERIA e where  a.cod_acct_no=e.cod_acct_no   and e.FLG_MNT_STATUS ='A')||'|'||
    c.cod_23||'|'||
    lpad(trim(a.cod_cc_brn),4,0)||'|'||

    (select min( o.dat_eff)  from ch_acct_od_hist o where a.cod_acct_no=o.cod_acct_no )
from    
    ch_acct_mast a,

    ch_acct_cbr_codes c,
    ba_cc_brn_mast d

where 
    a.flg_mnt_status ='A'

    and c.flg_mnt_status ='A'
    and a.cod_acct_no= c.cod_acct_no(+)
    and a.cod_cc_brn=d.cod_cc_brn 

    and a.cod_prod in (
    299,200,804,863,202,256,814,232,182,844,279,830,802,833,864,
    813,862,178,205,801,235,897,231,187,229,847,164,868,805,207,
    250,837,274,253,831,893,201,809,846,819,820,845,811,843,285,
    894,284,817,832,278,818,810,181,826,867,825,848,871,866,895,
    770,806,827,835,838,881,853,188,816,293,298)

查询计划:

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 4253465430

------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name                       | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |
------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                            |   733K|   125M|       |   468K  (1)|999:59:59 |       |       |
|   1 |  TABLE ACCESS BY INDEX ROWID        | AC_ACCT_PREFERENCES        |     1 |    26 |       |     3   (0)| 00:01:05 |       |       |
|*  2 |   INDEX UNIQUE SCAN                 | IN_AC_ACCT_PREFERENCES_1   |     1 |       |       |     2   (0)| 00:00:43 |       |       |
|   3 |   PARTITION HASH SINGLE             |                            |     1 |    31 |       |     3   (0)| 00:01:05 |   KEY |   KEY |
|   4 |    TABLE ACCESS BY LOCAL INDEX ROWID| AC_ACCT_PLAN_CRITERIA      |     1 |    31 |       |     3   (0)| 00:01:05 |   KEY |   KEY |
|*  5 |     INDEX UNIQUE SCAN               | IN_AC_ACCT_PLAN_CRITERIA_1 |     1 |       |       |     2   (0)| 00:00:43 |   KEY |   KEY |
|   6 |     SORT AGGREGATE                  |                            |     1 |    29 |       |            |          |       |       |
|   7 |      FIRST ROW                      |                            |     1 |    29 |       |     3   (0)| 00:01:05 |       |       |
|*  8 |       INDEX RANGE SCAN (MIN/MAX)    | IN_CH_ACCT_OD_HIST_1       |     1 |    29 |       |     3   (0)| 00:01:05 |       |       |
|   9 |  HASH UNIQUE                        |                            |   733K|   125M|   139M|   468K  (1)|999:59:59 |       |       |
|* 10 |   HASH JOIN                         |                            |   733K|   125M|       |   439K  (1)|999:59:59 |       |       |
|* 11 |    TABLE ACCESS FULL                | BA_CC_BRN_MAST             |  3259 |   136K|       |    31   (0)| 00:11:04 |       |       |
|* 12 |    HASH JOIN                        |                            |   747K|    97M|    61M|   439K  (1)|999:59:59 |       |       |
|  13 |     PARTITION HASH ALL              |                            |   740K|    52M|       |   286K  (1)|999:59:59 |     1 |    64 |
|* 14 |      TABLE ACCESS FULL              | CH_ACCT_MAST               |   740K|    52M|       |   286K  (1)|999:59:59 |     1 |    64 |
|* 15 |     TABLE ACCESS FULL               | CH_ACCT_CBR_CODES          |  9154K|   541M|       |   117K  (1)|699:41:01 |       |       |
------------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("COD_ACCT_NO"=:B1 AND "FLG_MNT_STATUS"='A' AND "COD_ENTITY_VPD"=TO_NUMBER(NVL(SYS_CONTEXT('CLIENTCONTEXT','entity_co
              de'),'0')))
   5 - access("COD_ACCT_NO"=:B1 AND "FLG_MNT_STATUS"='A' AND "COD_ENTITY_VPD"=TO_NUMBER(NVL(SYS_CONTEXT('CLIENTCONTEXT','entity_co
              de'),'0')))
   8 - access("COD_ACCT_NO"=:B1)
       filter("COD_ENTITY_VPD"=TO_NUMBER(NVL(SYS_CONTEXT('CLIENTCONTEXT','entity_code'),'0')))
  10 - access("COD_CC_BRN"="COD_CC_BRN")
  11 - filter("COD_ENTITY_VPD"=TO_NUMBER(NVL(SYS_CONTEXT('CLIENTCONTEXT','entity_code'),'0')))
  12 - access("COD_ACCT_NO"="COD_ACCT_NO")
  14 - filter(("COD_PROD"=164 OR "COD_PROD"=178 OR "COD_PROD"=181 OR "COD_PROD"=182 OR "COD_PROD"=187 OR "COD_PROD"=188 OR
              "COD_PROD"=200 OR "COD_PROD"=201 OR "COD_PROD"=202 OR "COD_PROD"=205 OR "COD_PROD"=207 OR "COD_PROD"=229 OR "COD_PROD"=231 OR
              "COD_PROD"=232 OR "COD_PROD"=235 OR "COD_PROD"=250 OR "COD_PROD"=253 OR "COD_PROD"=256 OR "COD_PROD"=274 OR "COD_PROD"=278 OR
              "COD_PROD"=279 OR "COD_PROD"=284 OR "COD_PROD"=285 OR "COD_PROD"=293 OR "COD_PROD"=298 OR "COD_PROD"=299 OR "COD_PROD"=770 OR
              "COD_PROD"=801 OR "COD_PROD"=802 OR "COD_PROD"=804 OR "COD_PROD"=805 OR "COD_PROD"=806 OR "COD_PROD"=809 OR "COD_PROD"=810 OR
              "COD_PROD"=811 OR "COD_PROD"=813 OR "COD_PROD"=814 OR "COD_PROD"=816 OR "COD_PROD"=817 OR "COD_PROD"=818 OR "COD_PROD"=819 OR
              "COD_PROD"=820 OR "COD_PROD"=825 OR "COD_PROD"=826 OR "COD_PROD"=827 OR "COD_PROD"=830 OR "COD_PROD"=831 OR "COD_PROD"=832 OR
              "COD_PROD"=833 OR "COD_PROD"=835 OR "COD_PROD"=837 OR "COD_PROD"=838 OR "COD_PROD"=843 OR "COD_PROD"=844 OR "COD_PROD"=845 OR
              "COD_PROD"=846 OR "COD_PROD"=847 OR "COD_PROD"=848 OR "COD_PROD"=853 OR "COD_PROD"=862 OR "COD_PROD"=863 OR "COD_PROD"=864 OR
              "COD_PROD"=866 OR "COD_PROD"=867 OR "COD_PROD"=868 OR "COD_PROD"=871 OR "COD_PROD"=881 OR "COD_PROD"=893 OR "COD_PROD"=894 OR
              "COD_PROD"=895 OR "COD_PROD"=897) AND "FLG_MNT_STATUS"='A' AND "COD_ENTITY_VPD"=TO_NUMBER(NVL(SYS_CONTEXT('CLIENTCONTEXT','entity_
              code'),'0')))
  15 - filter("FLG_MNT_STATUS"='A' AND "COD_ENTITY_VPD"=TO_NUMBER(NVL(SYS_CONTEXT('CLIENTCONTEXT','entity_code'),'0')))

考虑到每个表包含100多个列,我在上传整个表定义时受到限制。但请查看where子句中访问的列的以下详细信息。希望这可以帮助。

Columns     Type    Nullable
cod_acct_no CHAR(16)    N
FLG_MNT_STATUS  CHAR(1)     N 
cod_23          VARCHAR2(360)   Y
cod_cc_brn  NUMBER(5)   N
cod_prod    NUMBER          N

2 个答案:

答案 0 :(得分:2)

我希望这可以降低成本。

select 
distinct rtrim(a.cod_acct_no)||'|'||
a.cod_prod||'|'||
to_char(a.dat_acct_open,'Mon DD YYYY HH:MMAM')||'|'||
a.cod_acct_title||'|'||
a.cod_acct_stat||'|'||
ltrim(to_char(a.amt_od_limit,'99999999999999999990.999999'))||'|'||
ltrim(to_char(a.bal_book,'99999999999999999990.999999'))||'|'||
a.flg_idd_auth||'|'||
a.flg_mnt_status||'|'||
rtrim(c.cod_acct_no)||'|'||
c.cod_10||'|'||
d.nam_branch||'|'||
d.nam_cc_city||'|'||
d.nam_cc_state||'|'||
c.cod_1||'|'||
c.cod_14||'|'||
num_14||'|'||
a.cod_cust||'|'||
c.cod_last_mnt_chkrid||'|'||
c.dat_last_mnt||'|'||
c.ctr_updat_srlno||'|'||       
c.cod_20||'|'||            
c.num_16||'|'||
c.cod_14||'|'||                
c.num_10  ||'|'||
a.flg_classif_reqd||'|'||

g.cod_classif_plan_id||'|'||g.cod_classif_plan_id
 ||'|'||
 e.dat_cam_expiry ||'|'||
c.cod_23||'|'||
lpad(trim(a.cod_cc_brn),4,0)||'|'||
(select min( o.dat_eff)  from ch_acct_od_hist o where a.cod_acct_no=o.cod_acct_no )
from    
ch_acct_mast a
JOIN ch_acct_cbr_codes c
ON a.flg_mnt_status ='A'
 and c.flg_mnt_status ='A'
 and a.cod_acct_no= c.cod_acct_no(+)
JOIN    ba_cc_brn_mast d
a.cod_cc_brn=d.cod_cc_brn 
JOIN ac_acct_preferences g 
ON a.cod_acct_no=g.cod_acct_no AND g.FLG_MNT_STATUS = 'A'
INNER JOIN flexprod_host.AC_ACCT_PLAN_CRITERIA e
ON a.cod_acct_no=e.cod_acct_no   and e.FLG_MNT_STATUS ='A'

WHERE a.cod_prod in (
299,200,804,863,202,256,814,232,182,844,279,830,802,833,864,
813,862,178,205,801,235,897,231,187,229,847,164,868,805,207,
250,837,274,253,831,893,201,809,846,819,820,845,811,843,285,
894,284,817,832,278,818,810,181,826,867,825,848,871,866,895,
770,806,827,835,838,881,853,188,816,293,298)

答案 1 :(得分:1)

<强> 1。不要害怕全表扫描。如果正在访问表中大部分行,则使用散列连接/全表扫描比嵌套循环/索引扫描更有效。

<强> 2。修复统计信息并重新分析对象。 999小时读取表格?这可能是一个优化器bug,对于一些荒谬的值有一个dba看select * from sys.aux_stats$;。 时间不是很有用,但是如果你的一个预测值显着偏离,那么你需要检查所有这些值。您应该重新收集所有相关表格的统计数据。除非有充分的理由,否则请使用默认设置。例如,exec dbms_stats.gather_table_stats('your_schema_name','CH_ACCT_MAST');

第3。看看基数。棒球场中的Rows估计值是多少?它们几乎永远不会是完美的,但是如果它们超过它们的话 一个或两个数量级可能会导致问题。寻找第一个显着差异并尝试纠正它。

<强> 4。代码更改。 @Santhosh有一个好主意,使用ANSI连接重新编写并手动取消子查询。虽然我认为你应该 尝试取消其他子查询。 Oracle可以自动取消子查询,但子查询"contain aggregate functions"则不会。

<强> 5。禁用VPD 看起来正在转换此查询。确保您完全了解它正在做什么以及为什么。在调试此问题时,您可能想要暂时禁用VPD。

<强> 6。并行即可。由于其中一些表很大,您可能需要添加并行提示。但要小心,它很容易用完 资源。在你这样做之前尽量做好计划。