合 Oracle一个走了索引为啥还像蜗牛一样的案例
Tags: Oracle
现象及解决
最近发现一个同事的一个建表sql跑了一天的时间了还没有跑完的迹象,于是决定对其优化优化,原sql如下:
create table csy_zj2_acct_0628_t2 tablespace users nologging as
SELECT
A.*,
MONTHS_BETWEEN(TO_DATE('201406',
'yyyymm'),
TO_DATE(SUBSTR(TO_CHAR(A.DATE_OPENED_ACCT,
'yyyymmdd'),
1,
6),
'yyyymm')) AS MOB,
B.CHINESE_NAME,
B.GENDER,
B.BIRTHDAY,
B.CERTIFICATION_NO,
B.CUST_TYPE,
B.MOBILE_PHONE,
B.BILLING_ADDR,
B.HOME_ADDR,
B.EMPLOYER,
B.EMPLOYER_ADDR
FROM PUB_SJCJ.csy_zj2_ACCT_0628_T1 A,
RISKREPT.RKO_AMNA B
WHERE A.PARTY_NO = B.PARTY_NO
AND LENGTH(B.MOBILE_PHONE) = 11
AND B.MOBILE_PHONE LIKE '1%'
;
sql看着很简单,从外表上看没有什么问题,老规矩,先看看执行计划再说,找到sqlid,然后在sqlplus中执行
SELECT *** FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('ghfrjwd78yf2q',0,'advanced')); 得到内存中的执行计划,如下图:**
执行计划很简单,先扫描表RKO_AMNA上的索引IDX_RKO_AMNA_MBP,然后回表读,然后做2次NL连接操作,即执行计划路径为:5->4->6->3->7->2->1->0 ,cost花费也不是很高,但是我们从Predicate Information中看到一个异常的访问路径,就是第5步,按照道理第5步应该走的是filter过滤的,但是现在成了access访问了,凭经验估计是索引走错了,应该走RKO_AMNA上的PARTY_NO列的索引,当然这只是猜测,我们看一下IDX_RKO_AMNA_MBP是属于哪个列上的就真相大白了,好吧,先看看2个表的数据量吧,因为任何离开数据量谈优化都是没有意义的。
select *** from vw_table_lhr v where v.TABLE_NAME='RKO_AMNA';**
select *** from vw_table_lhr v where v.TABLE_NAME='CSY_ZJ2_ACCT_0628_T1';**
可以看出2个表都不是分区表,但是数据量稍微大点,一个2000W,一个1000W,分析日期都是最近分析的,但是不至于跑这么慢吧,再看看IDX_RKO_AMNA_MBP是属于哪个列上的索引呢?
SELECT *****
FROM vw_table_index_lhr v
WHERE v.TABLE_NAME = 'RKO_AMNA';
可以看出IDX_RKO_AMNA_MBP是属于MOBILE_PHONE列上的索引,至此说明我们之前的猜测是合理的,oracle每次做nl连接都是去访问索引IDX_RKO_AMNA_MBP的,而不是走唯一索引PK_RKO_AMNA的,操蛋呀,有唯一索引不走,走什么普通索引呀,,,,真是的,,,,,问题找见了那就对其优化优化呗,想了想采用hint来影响其执行计划吧,考虑到数据量大,所以不建议做nl连接,那就做hash连接吧,且让小表做驱动表,这里涉及到表之间的连接关系,有关这一方面的内容这里暂且给大家一个图,详细内容以后再写吧。
优化后sql如下:
create table csy_zj2_acct_0628_t2 tablespace users nologging as
SELECT /*+leading(a) index(b,PK_RKO_AMNA)*/
A.*,
MONTHS_BETWEEN(TO_DATE('201406',
'yyyymm'),
TO_DATE(SUBSTR(TO_CHAR(A.DATE_OPENED_ACCT,
'yyyymmdd'),
1,
6),
'yyyymm')) AS MOB,
B.CHINESE_NAME,
B.GENDER,
B.BIRTHDAY,
B.CERTIFICATION_NO,
B.CUST_TYPE,
B.MOBILE_PHONE,
B.BILLING_ADDR,
B.HOME_ADDR,
B.EMPLOYER,
B.EMPLOYER_ADDR
FROM PUB_SJCJ.csy_zj2_ACCT_0628_T1 A,