oracle 验证流水存在性火箭试优化
在生产中经常遇到“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 验证流水存在性火箭试优化的更多相关文章
- ORACLE当中自定义函数性优化浅析
为什么函数影响性能 在SQL语句中,如果不合理的使用函数(Function)就会严重影响性能,其实这里想说的是PL/SQL中的自定义函数,反而对于一些内置函数而言,影响性能的可能性较小.那么为什么SQ ...
- oracle capability i/o(压力測试数据库serveri/o性能)
今天是2014-04-21,今天简单仅仅说明一下怎么影响重做数据的一个因素,那就是i/o吞吐量,oracle的介质恢复依赖于i/o,假设i/o存在瓶颈,那么势必会影响备库的介质恢复. 那么i/o st ...
- Oracle 表三种连接方式(sql优化)
在查看sql执行计划时,我们会发现表的连接方式有多种,本文对表的连接方式进行介绍以便更好看懂执行计划和理解sql执行原理. 一.连接方式: 嵌套循环(Nested Loops (NL)) (散列)哈希 ...
- 一则简单演示样例看Oracle的“无私”健壮性
Oracle的强大之处就在于他能总帮助让你选择正确的运行计划,即使你给了它错误的指示. 实验: 1. 创建測试表: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZ ...
- oracle PLSQL 多结果集嵌套循环处理优化
oracle多结果集嵌套循环处理优化 --性能差 begin for a in (select id,name,sex,idcard from people) loop for b in (selec ...
- Oracle中索引的使用 索引性能优化调整
索引是由Oracle维护的可选结构,为数据提供快速的访问.准确地判断在什么地方需要使用索引是困难的,使用索引有利于调节检索速度. 当建立一个索引时,必须指定用于跟踪的表名以及一个或多个表列.一旦建立了 ...
- oracle如何进行索引监控分析和优化
在生产环境.我们会发现: ① 索引表空间 I/O 非常高 ② "db file sequential read" 等待事件也比较高 这种迹象表明.整个数据库系统.索引的 ...
- 【转】Oracle Freelist和HWM原理及性能优化
文章转自:http://www.wzsky.net/html/Program/DataBase/74799.html 近期来,FreeList的重要作用逐渐为Oracle DBA所认识,网上也出现一些 ...
- Oracle RAC cache fusion原理測试
Oracle RAC cache fusion是RAC最核心的工作机制.他把全部实例的SGA虚拟成一个大的SGA区,每当不同的实例请求同样的数据块,这个数据块就须要在实例间进行传递. 那究竟什么时候传 ...
- Oracle多表连接效率,性能优化
Oracle多表连接,提高效率,性能优化 (转) 执行路径:ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用:我们发现,单表数据的统计比多表统计的速度完全是两个概念.单表统计可能只 ...
随机推荐
- Kafka的系统架构和API开发
系统架构 主题topic和分区partition topic Kafka中存储数据的逻辑分类:你可以理解为数据库中"表"的概念:比如,将app端日志.微信小程序端日志.业务库订单表 ...
- Vue_Django 登录注册+图书管理系统
Vue前端 注册页面 点击查看代码 <template> <div class="register"> <el-row :gutter="2 ...
- @Target元注解的使用
@Target注解标记另外的注解用于限制此注解可以应用哪种Java元素类型.先看Java SE 8中@Target是如何声明的: package java.lang.annotation; publi ...
- C++面试八股文:static_cast了解一下?
某日二师兄参加XXX科技公司的C++工程师开发岗位第20面: 面试官:C++中支持哪些类型转换? 二师兄:C++支持C风格的类型转换,并在C++11引入新的关键字规范了类型转换. 二师兄:C++11引 ...
- 基于 Probe 的实时全局光照方案(Probe-based Global Illumination)
目录 Precomputed Probe 预放置 probes 四面体镶嵌(Tetrahedral Tessellations) Indirect Light Cache Volumetric Lig ...
- 投个 3D 冰壶,上班玩一玩
本篇文章将介绍如何使用物理引擎和图扑 3D 可视化技术来呈现冰壶运动的模拟. Oimo.js 物理引擎 Oimo.js 是一个轻量级的物理引擎,它使用 JavaScript 语言编写,并且基于 Oi ...
- C语言循环坑 -- continue的坑
文章目录 前言 一.continue语法 1.continue的作用 2.语法 二.大坑项目 题目 分析 正确写法 三.进坑调试 第一种 第二种 总结 前言 在使用continue和break时,会出 ...
- webshell工具流量特征
常见的webshell管理工具及流量特征 菜刀 作为老牌 Webshell 管理神器,中国菜刀的攻击流量特征明显,容易被各类安全设备检测,实际场景中越来越少使用,加密 Webshell 正变得日趋流行 ...
- C#中DataTable的一些使用(后续继续补充)
C#中DataTable的一些使用 新建一个DataTable DataTable table = new DataTable(); table.Columns.Add("姓名", ...
- 你不知道的 HTTP Referer
前言 上周突然发现自己的自己站点的图片全都403了,之前还是好好的,图片咋就全都访问不了呢?由于我每次发文章都是先发了掘金,然后再从掘金拷贝到我自己的站点,这样我就不用在自己的站点去上传图片了,非常方 ...