以下这句SQL是从PLM中获取代办工作流的。没优化前SQL语句执行一次大概4000ms(4秒)。

 select ch.change_number changeNumber, f.text changeDetail, u1.last_name creator,
l.value status, to_char(create_date,'yyyy-mm-dd hh24:mi:ss') createDate,
so.signoff_status type
from agile.change ch
inner join agile.workflow_process wp on (ch.id=wp.change_id and ch.status=wp.state and wp.changed_by is null)
inner join agile.signoff so on wp.id=so.process_id and so.signoff_status in (0,4) and so.required in(1,5)
inner join agile.agileuser u on u.id=so.user_assigned
inner join agile.langtable l on (ch.status=l.id and l.type=4450 and l.langid=4)
inner join agile.agileuser u1 on ch.originator=u1.id
left join agile.agile_flex f on f.id=ch.id and f.attid=2017
where (ch.subclass in (2473549,2473495,1,2475794,2473579,2474897,2473519,2480885,2479577,2473531,2485198,2479783)
or (ch.subclass = 2478248 and l.value = '审批'))
and u.email ='zhangsan@kedacom.com'

使用autotrace分析sql

 set autotrace on
set timing on

分析结果如下:

Elapsed: 00:00:00.008
Plan hash value: 1883359798 ------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 24 | 5280 | 954 (1)| 00:00:12 |
| 1 | NESTED LOOPS OUTER | | 24 | 5280 | 954 (1)| 00:00:12 |
| 2 | NESTED LOOPS | | 22 | 3564 | 921 (1)| 00:00:12 |
| 3 | NESTED LOOPS | | 22 | 3234 | 910 (1)| 00:00:11 |
| 4 | NESTED LOOPS | | 56 | 6328 | 882 (1)| 00:00:11 |
| 5 | NESTED LOOPS | | 156 | 11076 | 804 (1)| 00:00:10 |
| 6 | NESTED LOOPS | | 212 | 10176 | 592 (1)| 00:00:08 |
|* 7 | TABLE ACCESS FULL | AGILEUSER | 1 | 29 | 168 (1)| 00:00:03 |
|* 8 | TABLE ACCESS BY INDEX ROWID| SIGNOFF | 210 | 3990 | 424 (0)| 00:00:06 |
|* 9 | INDEX RANGE SCAN | SIGNOFF_IDX4 | 1120 | | 3 (0)| 00:00:01 |
|* 10 | TABLE ACCESS BY INDEX ROWID | WORKFLOW_PROCESS | 1 | 23 | 1 (0)| 00:00:01 |
|* 11 | INDEX UNIQUE SCAN | WF_PROCESS_PK | 1 | | 1 (0)| 00:00:01 |
|* 12 | TABLE ACCESS BY INDEX ROWID | CHANGE | 1 | 42 | 1 (0)| 00:00:01 |
|* 13 | INDEX UNIQUE SCAN | CHANGE_PK | 1 | | 1 (0)| 00:00:01 |
|* 14 | TABLE ACCESS BY INDEX ROWID | LANGTABLE | 1 | 34 | 1 (0)| 00:00:01 |
|* 15 | INDEX UNIQUE SCAN | LANGTABLE_PK | 1 | | 1 (0)| 00:00:01 |
| 16 | TABLE ACCESS BY INDEX ROWID | AGILEUSER | 1 | 15 | 1 (0)| 00:00:01 |
|* 17 | INDEX UNIQUE SCAN | AGILEUSER_PK | 1 | | 1 (0)| 00:00:01 |
| 18 | TABLE ACCESS BY INDEX ROWID | AGILE_FLEX | 1 | 58 | 2 (0)| 00:00:01 |
|* 19 | INDEX RANGE SCAN | AGILE_FLEX_UQ | 1 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------ Predicate Information (identified by operation id):
--------------------------------------------------- 7 - filter("U"."EMAIL"='fanjiangen@kedacom.com')
8 - filter(("SO"."REQUIRED"=1 OR "SO"."REQUIRED"=5) AND ("SO"."SIGNOFF_STATUS"=0 OR
"SO"."SIGNOFF_STATUS"=4))
9 - access("U"."ID"="SO"."USER_ASSIGNED")
10 - filter("WP"."CHANGED_BY" IS NULL)
11 - access("WP"."ID"="SO"."PROCESS_ID")
12 - filter(("CH"."SUBCLASS"=1 OR "CH"."SUBCLASS"=2473495 OR "CH"."SUBCLASS"=2473519 OR
"CH"."SUBCLASS"=2473531 OR "CH"."SUBCLASS"=2473549 OR "CH"."SUBCLASS"=2473579 OR
"CH"."SUBCLASS"=2474897 OR "CH"."SUBCLASS"=2475794 OR "CH"."SUBCLASS"=2478248 OR
"CH"."SUBCLASS"=2479577 OR "CH"."SUBCLASS"=2479783 OR "CH"."SUBCLASS"=2480885 OR
"CH"."SUBCLASS"=2485198) AND "CH"."STATUS"="WP"."STATE")
13 - access("CH"."ID"="WP"."CHANGE_ID")
14 - filter("CH"."SUBCLASS"=1 OR "CH"."SUBCLASS"=2473495 OR "CH"."SUBCLASS"=2473519 OR
"CH"."SUBCLASS"=2473531 OR "CH"."SUBCLASS"=2473549 OR "CH"."SUBCLASS"=2473579 OR
"CH"."SUBCLASS"=2474897 OR "CH"."SUBCLASS"=2475794 OR "CH"."SUBCLASS"=2479577 OR
"CH"."SUBCLASS"=2479783 OR "CH"."SUBCLASS"=2480885 OR "CH"."SUBCLASS"=2485198 OR
"CH"."SUBCLASS"=2478248 AND "L"."VALUE"='审批')
15 - access("L"."LANGID"=4 AND "L"."TYPE"=4450 AND "CH"."STATUS"="L"."ID")
17 - access("CH"."ORIGINATOR"="U1"."ID")
19 - access("F"."ID"(+)="CH"."ID" AND "F"."ATTID"(+)=2017)
filter("F"."ATTID"(+)=2017) Statistics
-----------------------------------------------------------
1 DB time
1 Requests to/from client
2 non-idle wait count
1 opened cursors cumulative
1 opened cursors current
1 pinned cursors current
58008 session uga memory
2 user calls

从解释计划中可以看出有2个地方预估时间很长,一个是对agileuser用户表,另一个是signoff,用户审批表。

用户表总共也就几千条记录,而且邮箱还是唯一的,所以资源耗费不是很大。而signoff表数据基数相当庞大,达到百万级。

虽然已经走了索引了,但是走的索引是审批用户的ID这个字段。对于绝大部分人来说,其下的数据不是很多。所以查询起来不会很慢。

但对于某些重要领导(大部分审批流都要他批的那种)数据量就会变得相当庞大。而这个SQL执行慢也恰好是遇到了这样的领导才会慢。

经过具体问题,根据某领导张三的用户ID可以在这张表中查询到2万多数据。也就是说数据库引擎根据现有索引找到该用户的记录后,还要从2万多记录中找到当前需要审批的记录。

分析至此,考虑将用户id以及sql语句中另外的2个条件加入组合索引。重新使用autotrace分析语句,结果如下:

Elapsed: 00:00:00.008
Plan hash value: 441713506 -------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 24 | 5280 | 622 (1)| 00:00:08 |
| 1 | NESTED LOOPS OUTER | | 24 | 5280 | 622 (1)| 00:00:08 |
| 2 | NESTED LOOPS | | 22 | 3564 | 589 (1)| 00:00:08 |
| 3 | NESTED LOOPS | | 22 | 3234 | 578 (1)| 00:00:07 |
| 4 | NESTED LOOPS | | 56 | 6328 | 550 (1)| 00:00:07 |
| 5 | NESTED LOOPS | | 156 | 11076 | 472 (1)| 00:00:06 |
| 6 | NESTED LOOPS | | 212 | 10176 | 260 (1)| 00:00:04 |
|* 7 | TABLE ACCESS FULL | AGILEUSER | 1 | 29 | 168 (1)| 00:00:03 |
| 8 | INLIST ITERATOR | | | | | |
| 9 | TABLE ACCESS BY INDEX ROWID| SIGNOFF | 210 | 3990 | 93 (2)| 00:00:02 |
|* 10 | INDEX RANGE SCAN | SIGNOFF_IDX_KD_1 | 210 | | 3 (34)| 00:00:01 |
|* 11 | TABLE ACCESS BY INDEX ROWID | WORKFLOW_PROCESS | 1 | 23 | 1 (0)| 00:00:01 |
|* 12 | INDEX UNIQUE SCAN | WF_PROCESS_PK | 1 | | 1 (0)| 00:00:01 |
|* 13 | TABLE ACCESS BY INDEX ROWID | CHANGE | 1 | 42 | 1 (0)| 00:00:01 |
|* 14 | INDEX UNIQUE SCAN | CHANGE_PK | 1 | | 1 (0)| 00:00:01 |
|* 15 | TABLE ACCESS BY INDEX ROWID | LANGTABLE | 1 | 34 | 1 (0)| 00:00:01 |
|* 16 | INDEX UNIQUE SCAN | LANGTABLE_PK | 1 | | 1 (0)| 00:00:01 |
| 17 | TABLE ACCESS BY INDEX ROWID | AGILEUSER | 1 | 15 | 1 (0)| 00:00:01 |
|* 18 | INDEX UNIQUE SCAN | AGILEUSER_PK | 1 | | 1 (0)| 00:00:01 |
| 19 | TABLE ACCESS BY INDEX ROWID | AGILE_FLEX | 1 | 58 | 2 (0)| 00:00:01 |
|* 20 | INDEX RANGE SCAN | AGILE_FLEX_UQ | 1 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 7 - filter("U"."EMAIL"='fanjiangen@kedacom.com')
10 - access("U"."ID"="SO"."USER_ASSIGNED" AND ("SO"."SIGNOFF_STATUS"=0 OR
"SO"."SIGNOFF_STATUS"=4) AND ("SO"."REQUIRED"=1 OR "SO"."REQUIRED"=5))
11 - filter("WP"."CHANGED_BY" IS NULL)
12 - access("WP"."ID"="SO"."PROCESS_ID")
13 - filter(("CH"."SUBCLASS"=1 OR "CH"."SUBCLASS"=2473495 OR "CH"."SUBCLASS"=2473519 OR
"CH"."SUBCLASS"=2473531 OR "CH"."SUBCLASS"=2473549 OR "CH"."SUBCLASS"=2473579 OR
"CH"."SUBCLASS"=2474897 OR "CH"."SUBCLASS"=2475794 OR "CH"."SUBCLASS"=2478248 OR
"CH"."SUBCLASS"=2479577 OR "CH"."SUBCLASS"=2479783 OR "CH"."SUBCLASS"=2480885 OR
"CH"."SUBCLASS"=2485198) AND "CH"."STATUS"="WP"."STATE")
14 - access("CH"."ID"="WP"."CHANGE_ID")
15 - filter("CH"."SUBCLASS"=1 OR "CH"."SUBCLASS"=2473495 OR "CH"."SUBCLASS"=2473519 OR
"CH"."SUBCLASS"=2473531 OR "CH"."SUBCLASS"=2473549 OR "CH"."SUBCLASS"=2473579 OR
"CH"."SUBCLASS"=2474897 OR "CH"."SUBCLASS"=2475794 OR "CH"."SUBCLASS"=2479577 OR
"CH"."SUBCLASS"=2479783 OR "CH"."SUBCLASS"=2480885 OR "CH"."SUBCLASS"=2485198 OR
"CH"."SUBCLASS"=2478248 AND "L"."VALUE"='审批')
16 - access("L"."LANGID"=4 AND "L"."TYPE"=4450 AND "CH"."STATUS"="L"."ID")
18 - access("CH"."ORIGINATOR"="U1"."ID")
20 - access("F"."ID"(+)="CH"."ID" AND "F"."ATTID"(+)=2017)
filter("F"."ATTID"(+)=2017) Statistics
-----------------------------------------------------------
1 CPU used by this session
1 Requests to/from client
2 non-idle wait count
1 opened cursors cumulative
1 opened cursors current
1 pinned cursors current
2 user calls
>>Query Run In:查询结果 3

从上面的结果可以看出,sql走入了新建的组合索引(SIGNOFF_IDX_KD_1),预估执行时间从原来的06秒变成02秒,cost也大幅度下降,整句SQL的执行时间也从4秒多下降到了200ms。

由此可见,索引对于查询的优化真是显而易见。

记一次SQL性能优化,查询时间从4000ms优化到200ms.的更多相关文章

  1. sql exist 优化查询时间

    1.非exist,查询需要20多秒 2.使用exist后 3.表连接也能优化

  2. PHP获取MySQL执行sql语句的查询时间

    //计时开始 runtime(); //执行查询 mysql_query($sql); //计时结束. echo runtime(1); //计时函数 function runtime($mode=0 ...

  3. sql server获取查询时间

    declare @d datetime set @d=getdate() /*你的SQL脚本开始*/ /*你的SQL脚本结束*/ select [语句执行花费时间(毫秒)]=datediff(ms,@ ...

  4. 计算sql语句的查询时间

    set statistics profile on set statistics io on set statistics time on go <这里写上你的语句...> go set ...

  5. (转载)PHP怎么获取MySQL执行sql语句的查询时间

    (转载自CSDN) 方法一: //计时开始 runtime(); //执行查询 mysql_query($sql); //计时结束. echo runtime(1); //计时函数 function ...

  6. 记一次sql server 性能调优,查询从20秒至2秒

    一.需求 需求很简单,就是需要查询一个报表,只有1个表,数据量大约60万左右,但是中间有些逻辑. 先说明一下服务器配置情况:1核CPU.2GB内存.机械硬盘.Sqlserver 2008 R2.Win ...

  7. SQL性能优化-查询条件与字段分开执行,union代替in与or,存储过程代替union

    PS:概要.背景.结语都是日常“装X”,可以跳过直接看优化历程 环境:SQL Server 2008 R2.阿里云RDS:辅助工具:SQL 审计 概要 一个订单列表分页查询功能,单从SQL性能来讲,从 ...

  8. SQL Server 2016 查询存储性能优化小结

    SQL Server 2016已经发布了有半年多,相信还有很多小伙伴还没有开始使用,今天我们来谈谈SQL Server 2016 查询存储性能优化,希望大家能够喜欢 作为一个DBA,排除SQL Ser ...

  9. 性能优化-查询最耗CPU的SESSION与SQL

    在linux 系统中 用top命令查出CPU最高的SPID,再将SPID给存储过程,可以查出该进程的SQLTEXT create or replace procedure pro_get_sqltex ...

随机推荐

  1. kafka-producer kerberos 原理和配置

    kerberos简单介绍 kerberos这一名词来源于希腊神话“三个头的狗---地狱之门守护者”后来沿用作为安全认证的概念,该系统设计上 采用客户端/服务器结构与DES(Data Encryptio ...

  2. linux scp传输文件命令

    scp  -r /opt/test root@192.168.2.105:/opt

  3. 解决java.lang.IllegalArgumentException: No converter found for return value of type 的问题

    controller返回一个dto,并且定义了@ResponseBody注解,表示希望将这个dto对象转换为json字符串返回给前端,但是运行时报错:nested exception is java. ...

  4. zabbix之 自定义(指定特定磁盘)监控io

    引言 zabbix自带的模板,并且完成了我们的一些比较常用的监控,现在我们如果想要监控我们磁盘的IO,这时候zabbix并没有给我们提供这么一个模板,所以我们需要自己来创建一个模板来完成磁盘IO的监控 ...

  5. LOJ 3057 「HNOI2019」校园旅行——BFS+图等价转化

    题目:https://loj.ac/problem/3057 想令 b[ i ][ j ] 表示两点是否可行,从可行的点对扩展.但不知道顺序,所以写了卡时间做数次 m2 迭代的算法,就是每次遍历所有不 ...

  6. JavaScript中的匿名函数遇上!会怎么样

    通常,我们声明一个函数test){},可以通过test()来调用这个函数.但是,如果我们在这个函数声明的末尾加上(),解析器是无法理解的. function test(){ console.log(' ...

  7. linux中telnet后退出连接窗口的方法?

    linux中telnet后退出连接窗口 [root@a cron]# telnet www.baidu.com 80Trying 115.239.211.112...Connected to www. ...

  8. server2012 多用户远程桌面

    这个服务器是客户提供的,阿里云平台的服务器.版本是windows-server2012,拿过来的时候,只有一个windows系统,啥都没有. 我们公司的数据库开发设计人员,B/S开发人员,APK开发人 ...

  9. flutter学习地址

      Flutter - 不一样的跨平台解决方案: 关于Flutter,你想知道的都在这里了!: Flutter 时间表 2015 年 4 月,Flutter(最初代号 Sky)在 Dart Devel ...

  10. 学习 MeteoInfo二次开发教程(六)

    在教程(五)的基础上加了Faded,Grid_Fill,Grid_Point,Raster,Vector,Barb,Streamline 1.同样注意修改LegendStyleEnum改为Legend ...