在生产中经常遇到“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. Spring Boot实现高质量的CRUD-2

    (续前文) 5.Dao类 ​ ​ Dao类提供操作访问数据库表的接口方法.常规的CRUD,将考虑下列接口方法: ​ 1)插入单条对象记录: ​ 2)批量插入对象记录: ​ 3)修改单条对象记录: ​ ...

  2. 曲线艺术编程 coding curves 第十章 螺旋曲线(SPIRALS)

    原作:Keith Peters https://www.bit-101.com/blog/2022/11/coding-curves/ 译者:池中物王二狗(sheldon) 源码:github: ht ...

  3. StencilJs学习之组件装饰器

    stenciljs 可以方便的构建交互式组件 支持以下装饰器 component state prop watch method element event listen Component 装饰器 ...

  4. MySql InnoDB 存储引擎表优化

    一.InnoDB 表存储优化 1.OPTIMIZE TABLE 适时的使用 OPTIMIZE TABLE 语句来重组表,压缩浪费的表空间.这是在其它优化技术不可用的情况下最直接的方法.OPTIMIZE ...

  5. 【C#/.NET】使用Automapper映射record类型

    ​ 当使用Automapper进行对象映射时,通常我们会使用POCO(Plain Old CLR Object)类作为源对象和目标对象.然而,自从C# 9引入了record类型,它们提供了更简洁.不可 ...

  6. XTTS系列之四:迷迷糊糊的并行度

    项目测试组又反馈一个问题,XTTS执行全量备份速度慢,影响测试进度. 实际算了下,平均速度才150MB/s.. 这个速度在客户生产环境的确是不够看,首先询问是否开了并行,开了多少? 回复是说有开32个 ...

  7. Cisco命令中login和login local的区别

    login是开启远程登录密码验证,login local不但要求密码,还要求提供用户名 如果同时设置login和login local,login local有效 (config-line)#line ...

  8. Unity的IPostGenerateGradleAndroidProject:深入解析与实用案例

    Unity IPostGenerateGradleAndroidProject Unity是一款流行的跨平台游戏引擎,它支持多种平台,包括Android.在Unity中,我们可以使用IPostGene ...

  9. 【技术积累】Mysql中的SQL语言【技术篇】【三】

    聚合函数 SUM函数 在MySQL中,SUM函数是用于计算数值列的总和的聚合函数.它接受一个数值列作为参数,并返回该列中所有值的总和. 以下是一个使用SUM函数的示例: 假设我们有一个名为" ...

  10. Spring Cloud 之OpenFeign

    Spring Cloud 之OpenFeign 一:简介 ​ Feign是一个声明式(对比RestTemplate编程式)的服务客户端,即通过@FeignClient注解即可声明一个接口(interf ...