需求:一个SQL执行特别慢,无法返回结果,需要进行优化,最终返回结果即可。

一、SQL分析

二、尝试执行,观测执行计划

三、修改SQL

四、问题总结

一、SQL分析

)SQL文本,执行时间,执行用户
用户brjljk sql执行时间,2935分钟
sql_text
select c.hphm,
c.ccdjrq,
c.clpp1,
c.clxh,
c.zt,
c.syr,
c.wfsj,
c.wfxw,
c.dsr,
c.xxly,
c.syq,
c.wfsj1,
d.wfnr,
e.dlmc,
c.xxly1,
c.dsr1
from (select /*+ index(b idx_violation_wfsj)*/
a.hphm,
a.ccdjrq,
a.clpp1,
a.clxh,
a.zt,
a.syr,
a.wfsj,
a.wfxw,
a.dsr,
a.xxly,
a.syq,
b.wfsj wfsj1,
b.wfxw wfxw1,
b.wfdd wfdd1,
b.xxly xxly1,
b.dsr dsr1
from A a
right join B b
on a.hphm = b.hphm
where a.wfsj <> b.wfsj
and (b.wfsj < add_months(a.wfsj, ) and
b.wfsj > add_months(a.wfsj, -))
and a.wfsj > to_date('2018-08-01', 'yyyy-mm-dd')
and a.wfsj < to_date('2018-09-01', 'yyyy-mm-dd')
order by a.hphm, a.wfsj, b.wfsj) c,
D d,
E e
where c.wfxw1 = d.wfxw
and c.wfdd1 = e.dldm 2)查询会话等待事件

SQL> select sid,serial#,event,sql_id,status,(sysdate-logon_time)*86400 as "s",

last_call_et,username,inst_id,MACHINE from gv$session where status='ACTIVE' and username is not null;

SID SERIAL# EVENT SQL_ID STATUS s LAST_CALL_ET USERNAME INST_ID MACHINE
---------- ---------- ------------------------------ ------------- -------- ---------- -------
1776 28345 db file sequential read 2vcdzpaknk46s ACTIVE 180100 176352 xxx 1 xx

3)查询sql文本

SQL> select sql_text from v$sqlarea where sql_id ='&a';
SQL> select sql_text from v$sqltext where sql_id ='2vcdzpaknk46s';
SQL> select sql_text from v$sqlstats where sql_id ='2vcdzpaknk46s';

4)查询执行计划

select * from table(dbms_xplan.display_cursor('&sql',null,'PEEKED_BINDS'));

SQL> select * from table(dbms_xplan.display_awr('2vcdzpaknk46s',null));

------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 129M(100)| |
| 1 | SORT ORDER BY | | 309 | 56238 | 129M (1)|432:58:14 |
| 2 | HASH JOIN | | 309 | 56238 | 129M (1)|432:58:14 |
| 3 | HASH JOIN | | 309 | 50985 | 129M (1)|432:58:13 |
| 4 | HASH JOIN | | 309 | 37389 | 129M (1)|432:58:13 |
| 5 | TABLE ACCESS FULL | SJS20181022 | 10455 | 847K| 891 (2)| 00:00:11 |
| 6 | TABLE ACCESS BY INDEX ROWID| VIO_VIOLATION | 144M| 5226M| 129M (1)|432:57:51 |
| 7 | INDEX FULL SCAN | IDX_VIOLATION_WFSJ | 144M| | 583K (1)| 01:56:47 |
| 8 | TABLE ACCESS FULL | VIO_CODEWFDM | 1069 | 47036 | 13 (0)| 00:00:01 |
| 9 | TABLE ACCESS FULL | FRM_ROADITEM | 5212 | 88604 | 22 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------

5)查询SQL等待事件

select count(*),event,count(distinct session_id) from gv$active_session_history
where sql_id='2vcdzpaknk46s' group by event;
COUNT(*) EVENT COUNT(DISTINCTSESSION_ID)
---------- ------------------------------ -------------------------
27652 db file sequential read 1
22 gc cr block 2-way 1
258 gc cr disk read 1
293 1

6)查询执行计划最慢的步骤(failed)

select count(*),sql_plan_line_id
from gv$active_session_history
where sql_id='2vcdzpaknk46s'
group by sql_plan_line_id
order by 2;

--生产环境10.2.0.5,11g才有的字段

7)表碎片

表碎片会导致全表扫描更消耗资源,本次慢不是由于全表扫描的问题

8)数据量

通过dba_tables,num_rows,dba_segments,bytes查询得到信息如下

a表 hash join 驱动表,30万条记录

B表 hash join 被驱动表,1亿条记录,表100G大小

二、尝试执行,观测执行计划

1)确认优化重点四个表中,从执行计划看,重点为
| 6 | TABLE ACCESS BY INDEX ROWID| VIO_VIOLATION | 144M| 5226M| 129M (1)|432:57:51 |
| 7 | INDEX FULL SCAN | IDX_VIOLATION_WFSJ | 144M| | 583K (1)| 01:56:47 |
该SQL是a +b 的集合,转换为c最后与其它表进行关联查询 2)对a+b表的查询进行优化及测试 思路A,是否由于时间取值范围导致的问题
and (b.wfsj < add_months(a.wfsj, 12) and
b.wfsj > add_months(a.wfsj, -12))
and a.wfsj > to_date('2018-08-01', 'yyyy-mm-dd')
and a.wfsj < to_date('2018-09-01', 'yyyy-mm-dd') explain plan for select a.hphm,a.wfsj,b.wfsj from A a right join B b on a.hphm=b.hphm where b.wfsj > to_date('2017-01-01','yyyy-mm-dd') and b.wfsj <to_date('2019-01-01','yyyy-mm-dd') and a.wfsj>to_date('2018-08-01','yyyy-mm-dd') and a.wfsj<to_date('2018-09-01','yyyy-mm-dd') order by a.hphm,a.wfsj, b.wfsj; 1* select * from table(dbms_xplan.display()) PLAN_TABLE_OUTPUT
----------------------------------------------------------------------
Plan hash value: 1015943026 -----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 18958 | 629K| 115K (1)| 00:23:12 |
| 1 | SORT ORDER BY | | 18958 | 629K| 115K (1)| 00:23:12 |
|* 2 | TABLE ACCESS BY INDEX ROWID| VIO_VIOLATION | 2 | 34 | 13 (0)| 00:00:01 |
| 3 | NESTED LOOPS | | 18958 | 629K| 115K (1)| 00:23:12 |
|* 4 | INDEX FAST FULL SCAN | SJS20181022_IND_HPHM | 10455 | 173K| 277 (2)| 00:00:04 |
|* 5 | INDEX RANGE SCAN | IDX_VIOLATION_HPHM | 12 | | 3 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - filter("B"."WFSJ">TO_DATE(' 2017-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"B"."WFSJ"<TO_DATE(' 2019-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
4 - filter("A"."WFSJ">TO_DATE(' 2018-08-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"A"."WFSJ"<TO_DATE(' 2018-09-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
5 - access("A"."HPHM"="B"."HPHM") select * from table(dbms_xplan.display_cursor('004nmwuabm1qr',null,'PEEKED_BINDS')) PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------
SQL_ID 004nmwuabm1qr, child number 0
-------------------------------------
select a.hphm, a.ccdjrq, a.clpp1, a.clxh, a.zt,
a.syr, a.wfsj, a.wfxw, a.dsr, a.xxly,
a.syq, b.wfsj wfsj1, b.wfxw wfxw1, b.wfdd wfdd1,
b.xxly xxly1, b.dsr dsr1 from A a right join
B b on a.hphm=b.hphm where (b.wfsj < add_months(a.wfsj, 12) and
b.wfsj >add_months(a.wfsj, -12)) and a.wfsj>to_date('2018-08-01','yyyy-mm-dd') and
a.wfsj<to_date('2018-09-01','yyyy-mm-dd') order by a.hphm,a.wfsj, b.wfsj Plan hash value: 3321285990 PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 136K(100)| |
| 1 | SORT ORDER BY | | 309 | 37389 | 136K (1)| 00:27:23 |
|* 2 | TABLE ACCESS BY INDEX ROWID| VIO_VIOLATION | 1 | 38 | 13 (0)| 00:00:01 |
| 3 | NESTED LOOPS | | 309 | 37389 | 136K (1)| 00:27:23 |
|* 4 | TABLE ACCESS FULL | SJS20181022 | 10455 | 847K| 891 (2)| 00:00:11 |
|* 5 | INDEX RANGE SCAN | IDX_VIOLATION_HPHM | 12 | | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
--------------------------------------------------- 2 - filter(("B"."WFSJ"<ADD_MONTHS(INTERNAL_FUNCTION("A"."WFSJ"),12) AND
"B"."WFSJ">ADD_MONTHS(INTERNAL_FUNCTION("A"."WFSJ"),-12)))
4 - filter(("A"."WFSJ">TO_DATE(' 2018-08-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')
AND
"A"."WFSJ"<TO_DATE(' 2018-09-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')))
5 - access("A"."HPHM"="B"."HPHM") 32 rows selected. 结论A的考虑是错误的,add_months并不会导致执行计划消耗更多的资源 思路B:多表连接的问题? 让sql从hash join 转换为nest loop试试,本次sql 取消hint即可,
为了不增加服务器负担,
使用explain plan for 方式 SQL> explain plan for select a.hphm,a.wfsj,b.wfsj from A a
right join B b on a.hphm=b.hphm
where (b.wfsj < add_months(a.wfsj, 12) and b.wfsj >add_months(a.wfsj, -12))
and a.wfsj>to_date('2018-08-01','yyyy-mm-dd')
and a.wfsj<to_date('2018-09-01','yyyy-mm-dd') order by a.hphm,a.wfsj, b.wfsj; Explained. SQL> select * from table(dbms_xplan.display()); PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
Plan hash value: 1015943026
---------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 309 | 10506 | 115K (1)| 00:23:12 |
| 1 | SORT ORDER BY | | 309 | 10506 | 115K (1)| 00:23:12 |
|* 2 | TABLE ACCESS BY INDEX ROWID| VIO_VIOLATION | 1 | 17 | 13 (0)| 00:00:01 |
| 3 | NESTED LOOPS | | 309 | 10506 | 115K (1)| 00:23:12 |
|* 4 | INDEX FAST FULL SCAN | SJS20181022_IND_HPHM | 10455 | 173K| 277 (2)| 00:00:04 |
|* 5 | INDEX RANGE SCAN | IDX_VIOLATION_HPHM | 12 | | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - filter("B"."WFSJ"<ADD_MONTHS(INTERNAL_FUNCTION("A"."WFSJ"),12) AND
"B"."WFSJ">ADD_MONTHS(INTERNAL_FUNCTION("A"."WFSJ"),-12))
4 - filter("A"."WFSJ">TO_DATE(' 2018-08-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"A"."WFSJ"<TO_DATE(' 2018-09-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
5 - access("A"."HPHM"="B"."HPHM") 21 rows selected. 发现nest loop 方式挺快的,继续测试(上述测试只测试3个字段) 使用原SQLa+b的两个表SQL不做变动,执行测试,发现执行计划未改变; 使用需要优化的SQL文本,删除hint,进行explain plan for 进行测试,执行计划未改变

  

  

  

三、修改SQL

删除Hint,让SQL走nest loop 方式,10s内返回结果
SQL> select c.hphm,
c.ccdjrq,
c.clpp1,
c.clxh,
c.zt,
c.syr,
c.wfsj,
c.wfxw,
c.dsr,
c.xxly,
c.syq,
c.wfsj1,
d.wfnr,
e.dlmc,
c.xxly1,
c.dsr1
from (select
a.hphm,
a.ccdjrq,
a.clpp1,
a.clxh,
a.zt,
a.syr,
a.wfsj,
a.wfxw,
a.dsr,
a.xxly,
a.syq,
b.wfsj wfsj1,
b.wfxw wfxw1,
b.wfdd wfdd1,
b.xxly xxly1,
b.dsr dsr1
from A a
right join B b
on a.hphm = b.hphm
where a.wfsj <> b.wfsj
and (b.wfsj < add_months(a.wfsj, 12) and
b.wfsj > add_months(a.wfsj, -12))
and a.wfsj > to_date('2018-08-01', 'yyyy-mm-dd')
and a.wfsj < to_date('2018-09-01', 'yyyy-mm-dd')
order by a.hphm, a.wfsj, b.wfsj) c,
D d,
E e
where c.wfxw1 = d.wfxw
and c.wfdd1 = e.dldm;
52519 rows selected.
Elapsed: 00:00:05.08 Execution Plan
----------------------------------------------------------
Plan hash value: 2181500870 -----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 309 | 56238 | 136K (1)| 00:27:24 |
| 1 | SORT ORDER BY | | 309 | 56238 | 136K (1)| 00:27:24 |
|* 2 | HASH JOIN | | 309 | 56238 | 136K (1)| 00:27:24 |
|* 3 | HASH JOIN | | 309 | 50985 | 136K (1)| 00:27:23 |
|* 4 | TABLE ACCESS BY INDEX ROWID| VIO_VIOLATION | 1 | 38 | 13 (0)| 00:00:01 |
| 5 | NESTED LOOPS | | 309 | 37389 | 136K (1)| 00:27:23 |
|* 6 | TABLE ACCESS FULL | SJS20181022 | 10455 | 847K| 891 (2)| 00:00:11 |
|* 7 | INDEX RANGE SCAN | IDX_VIOLATION_HPHM | 12 | | 3 (0)| 00:00:01 |
| 8 | TABLE ACCESS FULL | VIO_CODEWFDM | 1069 | 47036 | 13 (0)| 00:00:01 |
| 9 | TABLE ACCESS FULL | FRM_ROADITEM | 5212 | 88604 | 22 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - access("B"."WFDD"="E"."DLDM")
3 - access("B"."WFXW"="D"."WFXW")
4 - filter("A"."WFSJ"<>"B"."WFSJ" AND "B"."WFSJ"<ADD_MONTHS(INTERNAL_FUNCTION("A"."WFSJ"),
12) AND "B"."WFSJ">ADD_MONTHS(INTERNAL_FUNCTION("A"."WFSJ"),-12))
6 - filter("A"."WFSJ">TO_DATE(' 2018-08-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"A"."WFSJ"<TO_DATE(' 2018-09-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
7 - access("A"."HPHM"="B"."HPHM") Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
211168 consistent gets
108 physical reads
116 redo size
3555229 bytes sent via SQL*Net to client
39003 bytes received via SQL*Net from client
3503 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
52519 rows processed

  

  

四、问题总结

1)使用Nest loop方式,被驱动表及时循环查询30万次,比想象中的快很多很多
2)本次sql未优化前走hash join方式的原因是,hint 索引是时间列,
而Nest loop方式需要驱动表的查询结果输出身份证,被驱动表拿着身份证,
去被驱动表中索取记录;驱动表在本次执行计划无变化,被驱动表从时间字段索引,转换走
IDX_VIOLATION_HPHM, 也就是说,由于索引的选择度的问题,Oracle认为 hash join的连接方式
优于 date索引(hint)找到对应的rowid,然后找到hphm字段值
3)今后,在使用hint前,通过测试,选择合适的hint

  

  

  

  

hint不当索引,影响多表连接方式,最终导致SQL执行缓慢的更多相关文章

  1. Oracle 表连接方式分析 .

    一 引言 数据仓库技术是目前已知的比较成熟和被广泛采用的解决方案,用于整和电信运营企业内部所有分散的原始业务数据,并通过便捷有效的数据访问手段,可以支持企业内部不同部门,不同需求,不同层次的用户随时获 ...

  2. 看懂Oracle执行计划、表连接方式

    看懂Oracle执行计划  原文:https://www.cnblogs.com/Dreamer-1/p/6076440.html 最近一直在跟Oracle打交道,从最初的一脸懵逼到现在的略有所知,也 ...

  3. Oracle的表连接方式

    Oracle的表连接方式: 1.Nl Join连接(嵌套连接) 2.Hash Join(哈希连接) 3.Merge Sort Join(排序合并连接) 各种连接的使用场景: 1. 排序合并连接是偏向于 ...

  4. Oracle多种表连接方式

    1. 内连接(自然连接) 2. 外连接 (1)左外连接 (左边的表不加限制) (2)右外连接(右边的表不加限制) (3)全外连接(左右两表都不加限制) 3. 自连接(同一张表内的连接) SQL的标准语 ...

  5. 数据库基础知识详解三:MVCC、范式以及表连接方式

    写在文章前:本系列文章用于博主自己归纳复习一些基础知识,同时也分享给可能需要的人,因为水平有限,肯定存在诸多不足以及技术性错误,请大佬们及时指正. 8.MVCC 多版本并发控制(Multi-Versi ...

  6. sql表连接方式

    表连接有几种? sql表连接分成外连接.内连接和交叉连接.   一.外连接 概述: 外连接包括三种,分别是左外连接.右外连接.全外连接. 对应的sql关键字:LEFT/RIGHT/FULL OUTER ...

  7. 数据库多表连接方式介绍-HASH-JOIN

    1.概述 hash join是一种数据库在进行多表连接时的处理算法,对于多表连接还有两种比较常用的方式:sort merge-join 和 nested loop. 为了比较清楚的介绍hash joi ...

  8. oracle执行计划之-表连接方式

    转载自:http://blog.csdn.net/tianlesoftware/article/details/5826546 在多表联合查询的时候,如果我们查看它的执行计划,就会发现里面有多表之间的 ...

  9. SQLAlchemy(2):多表操作 & 连接方式及原生SQL

    一对多:ForeignKey multitb_models.py import datetime from sqlalchemy import create_engine # 引入 创建引擎 from ...

随机推荐

  1. ECharts柱状图添加点击事件

    参考: https://zhuanlan.zhihu.com/p/33050579 https://blog.csdn.net/sophia_xiaoma/article/details/780559 ...

  2. python中bottle模块的使用

    1.简介 2.示例 2.1一个简单的bottle接口 # -*- coding: utf-8 -*- from bottle import route, request, run import jso ...

  3. js中用来操作字符串的相关的方法

    var str = "zhufengpeixun2015yangfanqihang"; 字符串也是存在索引和length的 str.length 获取字符串的长度(字符的个数) 第 ...

  4. swagger注释@API详细说明

    swagger是当前最好用的Restful  API文档生成的开源项目,通过swagger-spring项目实现了springMVC框架的无缝集成功能,方便生成restful风格的接口文档, 同时,s ...

  5. shell脚本学习之参数传递

    shell之参数传递 我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n.n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推…… 实例 以 ...

  6. [x] 封装、继承,多态

    那么多态的作用是什么呢,封装可以使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用. 而多态的目的则是为了接口重用.也就是说,不论传递过来的究竟是那个类的对象,函数都能够通过同一个接 ...

  7. Uva LV 2995 Image Is Everything 模拟,坐标映射,视图映射 难度: 1

    题目 https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_pr ...

  8. day11 第一类对象 闭包 迭代器

    今日主要内容: 1 . 第一类对象 -->函数名--> 变量名 2. 闭包 -->函数的嵌套 3. 迭代器 --> 固定的思想 for 循环 第一类对象  : 函数对象介意向变 ...

  9. 读书笔记 C#事件event浅析(一)

    在C#中,所谓event事件,就是一种特殊的委托.如果要声明事件,首先就要声明一个相对应的委托类型.按照流程来说,事件相当于委托类型往上升了一级似的,我是这样认为的. //1.先声明委托类型 publ ...

  10. lxml简单用法 解析网页

    import requests s=requests.Session() re=s.get(lgurl,headers=headers)  #此处s可以直接换成requests the_page=re ...