走了索引为啥还像蜗牛一样?

简介: 一个有关走了索引为啥还是这么慢的例子 现象及解决     最近发现一个同事的一个建表sql跑了一天的时间了还没有跑完的迹象,于是决定对其优化优...


一个有关走了索引为啥还是这么慢的例子



  1. 现象及解决


 

 

最近发现一个同事的一个建表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,然后回表读,然后做2NL连接操作,即执行计划路径为: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,

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,取出内存中的执行计(SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('as4mp6r714m2u',0,'advanced'));

 

 

似乎花费cost比优化之前多了,没关系,在oracle中没有绝对的东东,凭经验这个语句应该可以了,为了不丢人,自己先跑得试试,快的话再发给同事修改吧,跑的过程中顺便截取了一下sql的实时监控信息,除了pga占用的有点高其他还算正常吧。

 

这里列出sql实时监控的sql,如果可以连接到oracle的官方网站的话,可以这样运行:

SELECT dbms_sqltune.report_sql_monitor(sql_id => 'cg1vcg59qgbp7',

TYPE => 'active',

report_level => 'all'

)

FROM dual;

如果不能连接到官网,那么在本地安装了tomcat后,下载相应的文件之后,就可以在本机这样查看:

SELECT dbms_sqltune.report_sql_monitor(sql_id => 'cg1vcg59qgbp7',

TYPE => 'active',

report_level => 'all',

base_path => 'http://localhost:8080/sqlmon')

FROM dual;

有关sql实时监控的这一部分内容以后给大家写博客补上吧,具体html文件参考附件
img_e25d4fb2f8de1caf41a735ec53088516.pngsql实时监控_lhr.zip

 

 

 

最后跑完的时候我看了下大约就2个小时30分钟,还可以了,就这样吧。

 


  1. 与此相关还有一个例子,这里列出来供大家参考:


如果一张表上有多个索引且查询条件中多个列都用到了的话,有可能是没有走正确的索引,有的时候创建了组合索引,在用的时候没有走正确的索引,导致很慢。例:

 

SELECT t.qy,

t.ywb,

t.addressid,

t.assemblename,

t.addressid5_id,

t.meid,

t.me_name,

t.me_code,

t.me_spec_cn

FROM xt_addrescover_lhr t

WHERE t.meid = 426296

AND t.me_spec IN

('com.gxlu.ngrm.equipment.DP',

'com.gxlu.ngrm.equipment.InfoPoint',

'com.gxlu.ngrm.equipment.OBD',

'com.gxlu.ngrm.equipment.OFXHME');

 

 

以上查询语句中,xt_addrescover_lhrmeidme_spec都有索引,如果执行上边的语句可能会走me_spec列上的索引,这个时候导致很慢,几个小时也查询不出来,但是如果走meid的索引就很快了。

SELECT /*+index(t,IDX_ADDRESCOVER_MEID)*/

t.qy,

t.ywb,

t.addressid,

t.assemblename,

t.addressid5_id,

t.meid,

t.me_name,

t.me_code,

t.me_spec_cn

FROM xt_addrescover_lhr t

WHERE t.meid = 426296

AND t.me_spec IN

('com.gxlu.ngrm.equipment.DP',

'com.gxlu.ngrm.equipment.InfoPoint',

'com.gxlu.ngrm.equipment.OBD',

'com.gxlu.ngrm.equipment.OFXHME');

 

 


总结

    1.本文设计到 执行计划的查看、表之间的连接方式(常用3种)、11g新特性的sql的实时监控等方面的知识,由于篇幅原因没有一一列出,如果有需要以后再写写这些方面的东东吧,看网友需要吧

    2.Sql优化有很多经典的例子,但是最基本的都是网上列出来的需要注意的一些事项,本文的情况就属于表上多个索引的选择性问题

    3. 有关sql优化中索引这一部分是最重要的一部分,大家一定要活学活用

目录
相关文章
|
8月前
|
算法 前端开发 索引
2624. 蜗牛排序
2624. 蜗牛排序
49 0
|
8月前
|
存储 机器学习/深度学习 算法
六六力扣刷题哈希表之三数之和
六六力扣刷题哈希表之三数之和
65 0
|
存储 自然语言处理 索引
|
存储 算法 关系型数据库
面试官:索引是什么,如何实现?懵逼~
面试官:索引是什么,如何实现?懵逼~
|
存储 SQL 关系型数据库
覆盖索引这回事算是整明白了
覆盖索引这回事算是整明白了
280 0
覆盖索引这回事算是整明白了
|
存储 安全 Java
集合很简单?开什么玩笑?肝了一周,全是精华,万字讲解,面试再不怕集合问题了
ArrayList 是容量可变的⾮线程安全列表,使⽤数组实现,集合扩容时会创建更⼤的数组,把原有数组复制到新数组。⽀持对元素的快速随机访问,但插⼊与删除速度很慢。ArrayList 实现了 RandomAcess 标记接⼝,如果⼀个类实现了该接⼝,那么表示使⽤索引遍历⽐迭代器更快。
127 0
集合很简单?开什么玩笑?肝了一周,全是精华,万字讲解,面试再不怕集合问题了
|
存储 负载均衡 算法
HASH碰撞问题一直没真正搞懂?这下不用慌了
散列函数(英语:Hash function)又称散列算法、哈希函数,是一种从任何一种数据中创建小的数字“指纹”的方法。散列函数把消息或数据压缩成摘要,使得数据量变小,将数据的格式固定下来。该函数将数据打乱混合,重新创建一个叫做散列值(hash values,hash codes,hash sums,或hashes)的指纹。散列值通常用一个短的随机字母和数字组成的字符串来代表。
HASH碰撞问题一直没真正搞懂?这下不用慌了
|
存储 算法 Java
刷穿剑指offer-Day14-哈希表I 基础知识整理
刷穿剑指offer-Day14-哈希表I 基础知识整理
132 0
|
机器学习/深度学习 算法
一看就懂,一写就懵?搞懂回溯算法,一口气刷了20多道题(上)
回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。——摘自《百度百科》
220 0
一看就懂,一写就懵?搞懂回溯算法,一口气刷了20多道题(上)
|
算法
一看就懂,一写就懵?搞懂回溯算法,一口气刷了20多道题(中)
回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。——摘自《百度百科》
404 0
一看就懂,一写就懵?搞懂回溯算法,一口气刷了20多道题(中)

热门文章

最新文章