子查询优化的经典案例(三)

2014-11-24 10:11:22 · 作者: · 浏览: 14
AYMENT_ID" IS NULL)

15 - access("indexjoin_alias_012".ROWID="indexjoin_alias_011".ROWID)

19 - filter("T_COMPANY_ORGAN"."ORGAN_ID"='101')

21 - access("T_COMPANY_ORGAN"."ORGAN_ID"='101')

26 - access("T_COMPANY_ORGAN"."PARENT_ID"=NULL)

28 - access("TPC"."CHANGE_ID"="TPF"."CHANGE_ID")

31 - access("D"."COMPANY_ID"="E"."COMPANY_ID"(+))

55 rows selected

Statistics

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

21 recursive calls

0 db block gets

125082 consistent gets

21149 physical reads

0 redo size

2448 bytes sent via SQL*Net to client

656 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

4 sorts (memory)

0 sorts (disk)

11 rows processed

这个SQL要21秒才能跑完,逻辑读12W左右,问我能不能优化。优化这个SQL我只花了1分钟左右的时间,因为太简单了

你们看这个SQL是典型的JOIN,对付这种SQL肯定要让表走索引,但是从执行计划上看有个1千万行的表T_CONTRACT_MASTER走的是全表扫描,

T_POLICY_FEE 这个400W行的表也是走全表扫描,那么它不慢才怪呢,然后SQL的过滤条件有个in 子查询

(select

organ_id

from t_company_organ

start with organ_id = '101'

connect by prior organ_id = parent_id)

从执行计划上看,CBO对这儿子查询进行了unnest,因为通常情况下CBO认为子查询被unnest之后性能好于filter

于是我让盖尔查询 子查询返回多少行

select organ_id

from t_company_organ

start with organ_id = '101'

connect by prior organ_id = parent_id ---盖尔说它返回1行

对于子查询,如果它返回数据很少(这里返回1行),那么可以让它走filter, 而且filter基本上是在SQL最后去阶段执行,这样t_policy_fee就可以走索引了

所以我给这个子查询加了个HINT,禁止子查询扩展

view plainprint

select tpc.policy_id,

tcm.policy_code,

tpf.organ_id,

to_char(tpf.insert_time, 'YYYY-MM-DD') As insert_time,

tpc.change_id,

d.policy_code,

e.company_name,

f.real_name,

tpf.fee_type,

sum(tpf.pay_balance) as pay_balance,

c.actual_type,

tpc.notice_code,

d.policy_type,

g.mode_name as pay_mode

from t_policy_change tpc,

t_contract_master tcm,

t_policy_fee tpf,

t_fee_type c,

t_contract_master d,

t_company_customer e,

t_customer f,

t_pay_mode g

where tpc.change_id = tpf.change_id

and tpf.policy_id = d.policy_id

and tcm.policy_id = tpc.policy_id

and tpf.receiv_status = '1' ---这里原来没引号,是开发那SB搞忘了写'',我让盖尔添加上了,不添加上就没法用索引

and tpf.fee_status = 1

and tpf.payment_id is null

and tpf.fee_type = c.type_id

and tpf.pay_mode = g.mode_id

and d.company_id = e.company_id(+)

and d.applicant_id = f.customer_id(+)

and tpf.organ_id in

(select /*+ no_unnest */ --此处的HINT后加的

organ_id

from t_company_organ

start with organ_id = '101'

connect by prior organ_id = parent_id)

group by tpc.policy_id,

tpc.change_id,

tpf.fee_type,

to_char(tpf.insert_time, 'YYYY-MM-DD'),

c.actual_type,

d.policy_code,

g.mode_name,

e.company_name,

f.real_name,

tpc.notice_code,

d.policy_type,

tpf.organ_id,

tcm.policy_code

order by change_id, fee_type

SQL> select * from table(dbms_xplan.display);