在生产中经常遇到“select * from  tbl_IsExist where date=?”的SQL,经与开发人员沟通得知此SQL是验证流水存在性,若不存在则插入,若存在退出。

前台根据list的size值来判断符合条件的数据是否存在。我们构建测试表分析验证流水存在性的优化方向。

1、构建测试表

--创建测试表
drop table tbl_IsExist purge;
create table tbl_IsExist
(id number not null ,in_create date,in_remark varchar2(1000),
primary key(id)
);
--插入测试数据
insert into tbl_IsExist
select rownum,to_date(trunc(dbms_random.value(to_number(to_char(sysdate-5,'J')),to_number(to_char(sysdate,'J')))),'J'),rpad('*',1000,'*') from dual connect by rownum<20000;
--根据生产创建索引
SQL> create index ind_isexist_create on tbl_isexist(in_create); Index created.

由于生产环境date的数据是均匀分配的,对于in_create字段的处理符合生产规则。执行生产中捕获的SQL,查看其执行计划。

2、发现验证存在性的SQL执行计划是全表扫描,代价很高:

--设置输出参数
SQL> set linesize 2000
SQL> set autotrace on;
--执行查询脚本
SQL> select * from tbl_isexist where in_create=TO_DATE('2020-09-24 00:00:00','YYYY-MM-DD HH24:MI:SS'); 3962 rows selected. Execution Plan
----------------------------------------------------------
Plan hash value: 2271097464 ---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3269 | 1672K| 777 (1)| 00:00:01 |
|* 1 | TABLE ACCESS FULL | TBL_ISEXIST | 3269 | 1672K| 777 (1)| 00:00:01 |
--------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 1 - filter("IN_CREATE"=TO_DATE(' 2020-09-24 00:00:00', 'syyyy-mm-dd
hh24:mi:ss')) Note
-----
- dynamic statistics used: dynamic sampling (level=2) Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
3098 consistent gets
0 physical reads
0 redo size
90787 bytes sent via SQL*Net to client
3362 bytes received via SQL*Net from client
266 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
3962 rows processed

表上有供选择的索引,但是SQL并没有执行,此SQL的执行计划是全表扫描,cost为777,逻辑读3098数据块。若表中的记录很多,全表扫描的执行计划将耗用大量的逻辑读。
3、开始优化,验证流水存在性SQL

①优化思路1:

表中有可用索引,优化器未采纳是否由于代价高,进一步验证:

用hint强制走索引,查看执行计划
SQL> select /*+ INDEX(T IND_ISEXIST_CREATE)*/* from tbl_isexist T where in_create=TO_DATE('2020-09-24 00:00:00','YYYY-MM-DD HH24:MI:SS'); 3962 rows selected. Execution Plan
----------------------------------------------------------
Plan hash value: 1453123986 ----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3269 | 1672K| 2004 (1)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID BATCHED| TBL_ISEXIST | 3269 | 1672K| 2004 (1)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IND_ISEXIST_CREATE | 3269 | | 10 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - access("IN_CREATE"=TO_DATE(' 2020-09-24 00:00:00', 'syyyy-mm-dd hh24:mi:ss')) Note
-----
- dynamic statistics used: dynamic sampling (level=2) Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2648 consistent gets
0 physical reads
0 redo size
4126831 bytes sent via SQL*Net to client
3397 bytes received via SQL*Net from client
266 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
3962 rows processed

强制走索引cost是2004比走全表扫描代价更大,oracle是基于代价的优化器,故舍弃索引扫描的执行计划

②优化思路2:

在行数上做文章,验证流水存在性是否需要将所有记录都返回。因为在java中根据list的值不为0判断存在性,设想满足条件的第一条记录存在,岂不已经验证存在性。

现改写SQL查看其执行计划:

--只取第一条符合条件的记录,加限制条件rownum=1
SQL> select * from tbl_isexist where in_create=TO_DATE('2020-09-24 00:00:00','YYYY-MM-DD HH24:MI:SS') and rownum=1; Execution Plan
----------------------------------------------------------
Plan hash value: 1281543153 -----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 524 | 2 (0)| 00:00:01 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED | TBL_ISEXIST | 3269 | 1672K| 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | IND_ISEXIST_CREATE | | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 1 - filter(ROWNUM=1)
3 - access("IN_CREATE"=TO_DATE(' 2020-09-24 00:00:00', 'syyyy-mm-dd hh24:mi:ss')) Note
-----
- dynamic statistics used: dynamic sampling (level=2) Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
1725 bytes sent via SQL*Net to client
471 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

我们由取全部符合条件的记录,改为只取第一行符合条件的记录,cost由777降为2,逻辑读由3098降为3,提速几百倍,甚是欣喜。高兴之余,试想是否还有可优化空间。分析执行计划:INDEX RANGE SCAN花去了1个cost,TABLE ACCESS BY INDEX ROWID BATCHED也就是回表花去了1个cost(2-1)。

回表的原理:查询的列不在索引中,需要通过索引的rowid定位表记录,把需要的字段取出,展示给客户端。

③优化思路3:

不回表降低cost,在SQL返回的列上做文章。只显示索引“IND_ISEXIST_CREATE”的列in_create,既能降低cost也能满足需求,完全可以。

SQL> select in_create from tbl_isexist where in_create=TO_DATE('2020-09-24 00:00:00','YYYY-MM-DD HH24:MI:SS') and rownum=1;

Execution Plan
----------------------------------------------------------
Plan hash value: 3010836204 ----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 | 1 (0)| 00:00:01|
|* 1 | COUNT STOPKEY | | | | | |
|* 2 | INDEX RANGE SCAN | IND_ISEXIST_CREATE | 3269 | 29421 | 1 (0)| 00:00:01|
---------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 1 - filter(ROWNUM=1)
2 - access("IN_CREATE"=TO_DATE(' 2020-09-24 00:00:00', 'syyyy-mm-dd
hh24:mi:ss')) Note
-----
- dynamic statistics used: dynamic sampling (level=2) Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
556 bytes sent via SQL*Net to client
479 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

至此优化结束,代价从777降到1,逻辑读从3098降到2,可谓是火箭试的提速!

其他问题请关注目录:https://www.cnblogs.com/handhead/

oracle 验证流水存在性火箭试优化的更多相关文章

  1. ORACLE当中自定义函数性优化浅析

    为什么函数影响性能 在SQL语句中,如果不合理的使用函数(Function)就会严重影响性能,其实这里想说的是PL/SQL中的自定义函数,反而对于一些内置函数而言,影响性能的可能性较小.那么为什么SQ ...

  2. oracle capability i/o(压力測试数据库serveri/o性能)

    今天是2014-04-21,今天简单仅仅说明一下怎么影响重做数据的一个因素,那就是i/o吞吐量,oracle的介质恢复依赖于i/o,假设i/o存在瓶颈,那么势必会影响备库的介质恢复. 那么i/o st ...

  3. Oracle 表三种连接方式(sql优化)

    在查看sql执行计划时,我们会发现表的连接方式有多种,本文对表的连接方式进行介绍以便更好看懂执行计划和理解sql执行原理. 一.连接方式: 嵌套循环(Nested Loops (NL)) (散列)哈希 ...

  4. 一则简单演示样例看Oracle的“无私”健壮性

    Oracle的强大之处就在于他能总帮助让你选择正确的运行计划,即使你给了它错误的指示. 实验: 1. 创建測试表: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZ ...

  5. oracle PLSQL 多结果集嵌套循环处理优化

    oracle多结果集嵌套循环处理优化 --性能差 begin for a in (select id,name,sex,idcard from people) loop for b in (selec ...

  6. Oracle中索引的使用 索引性能优化调整

    索引是由Oracle维护的可选结构,为数据提供快速的访问.准确地判断在什么地方需要使用索引是困难的,使用索引有利于调节检索速度. 当建立一个索引时,必须指定用于跟踪的表名以及一个或多个表列.一旦建立了 ...

  7. oracle如何进行索引监控分析和优化

    在生产环境.我们会发现: ① 索引表空间 I/O 非常高     ② "db file sequential read" 等待事件也比较高   这种迹象表明.整个数据库系统.索引的 ...

  8. 【转】Oracle Freelist和HWM原理及性能优化

    文章转自:http://www.wzsky.net/html/Program/DataBase/74799.html 近期来,FreeList的重要作用逐渐为Oracle DBA所认识,网上也出现一些 ...

  9. Oracle RAC cache fusion原理測试

    Oracle RAC cache fusion是RAC最核心的工作机制.他把全部实例的SGA虚拟成一个大的SGA区,每当不同的实例请求同样的数据块,这个数据块就须要在实例间进行传递. 那究竟什么时候传 ...

  10. Oracle多表连接效率,性能优化

    Oracle多表连接,提高效率,性能优化 (转) 执行路径:ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用:我们发现,单表数据的统计比多表统计的速度完全是两个概念.单表统计可能只 ...

随机推荐

  1. CAPL 脚本对信号收发的判断

    在CAPL脚本中,您可以使用条件语句和CAN消息的收发函数来进行信号的判断和处理.以下是一些常见的CAPL脚本语句用于信号收发的判断: 1.判断消息是否收到 on message can_messag ...

  2. vulnhub-xxe靶场通关(xxe漏洞续)

    vulnhub-xxe靶场通关(xxe漏洞续) 下面简单介绍一个关于xxe漏洞的一个靶场,靶场来源:https://www.vulnhub.com 这里面有很多的靶场. 靶场环境需要自己下载:http ...

  3. MAUI Blazor 加载本地图片的解决方案

    前言 为了解决MAUI Blazor无法加载本地图片,https://github.com/dotnet/maui/issues/2907,所以写了这篇文章. 有token大佬珠玉在前,https:/ ...

  4. 2022-02-08 IValueConverter和StringFormat

    主页 后台 stringFormat

  5. Scala的基本使用

    @ 目录 Scala的基本使用 一.基础语法 1.1 变量 1.1.1 var和val 1.1.2 自动类型推断 1.2 数据类型 1.2.1 基础数据类型 1.2.2 增强数据类型 1.3 操作符 ...

  6. 通过 tree shaking 移除无用代码

    tree shaking 依赖于ES Module 的静态语法分析,在项目编译时移除无用的代码以减少文件体积. usedExports 在文件中,我们可能定义了变量但是暂时又没有用到,这样会造成空间的 ...

  7. Go的任务调度单元与并发编程

    摘要:本文由葡萄城技术团队于博客园原创并首发.转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 前言 本文主要介绍Go语言.进程.线程.协程的出现背景原因以及 ...

  8. mysql拓展

    事务定义 就是将一组SQL语句放在同一批次内去执行 如果一个sql语句出错,则改批次内的所有sql都将被取消执行 (1)原子性 一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作, ...

  9. selenium + python自动化环境搭建

    Selenium是一个用于Web应用程序测试的工具.Selenium测试直接运行在浏览器中,就像真正的用户在操作一样.支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firef ...

  10. windows和linux键值表

    windows系统下对应键值 {8,KEY_BACKSPACE}, {9,KEY_TAB}, {13,KEY_ENTER}, {16,KEY_LEFTSHIFT}, {17,KEY_LEFTCTRL} ...