最近在看《基于Oracle的SQL优化一书》,并做了笔记,作者的个人博客:http://www.dbsnake.net/

@

一、SQL执行过程简介

继上一篇博客Oracle的cursor学习笔记:Oracle的游标Cursor原理简介,再介绍oracle的绑定变量

介绍绑定变量之前,先介绍SQL执行过程和硬解析的概念:

执行sql的过程,会将sql的文本进行hash运算,得到对象的hash值,然后拿hash值,去Hash Buckets里遍历缓存对象句柄链表,找到对应的缓存对象句柄,然后就可以得到缓存对象句柄里对应sql执行计划、解析树等对象,所以执行相同的sql第二次执行时是会比较快的,因为不需要解析获取执行计划,解析树等对象,如果找不到库缓存对象句柄,就需要重新解析,这个过程解析过多,容易造成硬解析问题

硬解析:是指Oracle在执行目标SQL时,在库缓存中找不到可以重用的解析树和执行计划,而不得不从头开始解析目标SQL并生成相应的Parent Cursor和Child Cursor的过程。

软解析:是指Oracle在执行目标SQL时,在Library Cache中找到了匹配的Parent Cursor和Child Cursor,并将存储在Child Cursor中的解析树和执行计划直接拿过来重用,无须从头开始解析的过程。

ok,上面是SQL执行过程的简单介绍,由此可知,假如sql执行过程,在共享池里找不到执行计划、解析树等就会重现解析sql,生成执行计划和解析树等,这个过程是比较耗时间的,所以要想办法尽量不要重现解析sql,需要执行计划直接去共享池拿已经生成的

举个例子,select * from sys_user where userid='u10001';select * from sys_user where userid='u10002';,这两个很类似的sql在执行过程,生成的执行计划很有可能是不一样的,也就是说第一条sql执行后,第二条sql继续执行,假如发现找不到对应执行计划,就会再解析sql,重现生成session cursor和一对shared cursor(parent cursor和child cursor)

然后,我们不想重新解析sql,有什么方法?方法就是用绑定变量的方法

二、绑定变量典型用法

2.1、在SQL中绑定变量

绑定变量的典型用法就是用 :variable_name的形式,variable_name是自定义的变量名称,variabl_name可以是字母、数字或者字母和数字的组合

ok,上面的那种类型的sql,就可以用一条带绑定变量的sql来表示:

  1. select * from sys_user where userid = :u;

这样这种类型的一堆sql都只会解析一次,不用每条sql都解析一遍,可以很好的提高系统处理能力

ok,举个例子说明

环境准备:

  1. /* 随便建一张表*/
  2. create table t as select * from dba_objects;

注意,这些脚本只能在sqlplus或者PLSQL客户端的命令窗口执行

  1. /* 定义绑定变量vid */
  2. SQL> variable vid number;
  3. /* 给绑定变量赋值为2 */
  4. SQL> exec :vid := 2;

在sqlplus或者PLSQL客户端的命令窗口执行

  1. /* 通过绑定变量查询 */
  2. SQL> select * from t where object_id = :vid;
  1. /*通过性能视图查询SQL解析情况*/
  2. select a.*, b.name
  3. from v$sesstat a, v$statname b
  4. where a.statistic# = b.statistic#
  5. and a.sid = (select distinct sid from v$mystat)
  6. and b.name like '%parse%';
  1. /* 去共享池查询一下这种类型的SQL信息*/
  2. select sql_text, parse_calls, executions
  3. from v$sql
  4. where sql_text like 'select * from t where object_id=%';
  1. /* 通过共享池查询查询最慢的10条sql*/
  2. SELECT *
  3. FROM (select PARSING_USER_ID,
  4. EXECUTIONS,
  5. SORTS,
  6. COMMAND_TYPE,
  7. DISK_READS,
  8. sql_text
  9. FROM v$sqlarea
  10. order BY disk_reads DESC)
  11. where ROWNUM < 10;

2.2、在PL/SQL中使用绑定变量

  1. /* SQL语句使用绑定变量*/
  2. declare
  3. vc_empname varchar2(10);
  4. begin
  5. execute immediate 'select ename from t_emp where empno = :1'
  6. into vc_empname
  7. using 7369;
  8. dbms_output.put_line(vc_empname);
  9. end;
  10. /

往t_emp表写入一条数据,并统计是否执行成功,返回数值

  1. /*DML语句使用绑定变量*/
  2. declare
  3. vc_sql varchar2(2000);
  4. vc_number number;
  5. begin
  6. vc_sql := 'insert into t_emp(empno,ename,job) values(:1,:2,:3)';
  7. execute immediate vc_sql using 7990,'SMITH','HR';
  8. vc_number := sql%rowcount;
  9. dbms_output.put_line(to_char(vc_number));
  10. commit;
  11. end;
  12. /

所以绑定变量在pl/sql里的核心语法为:

  1. execute immediate [sql语句] using [变量]

2.3、PL/SQL批量绑定变量

例子来自《基于Oracle的SQL优化》一书,要实现的的是批量绑定变量,fetch关键字,将empno大于7900的职员信息打印出来

  1. declare
  2. cur_emp sys_refcursor;
  3. vc_sql varchar2(2000);
  4. type namelist is table of varchar2(10);
  5. enames namelist;
  6. CN_BATCH_SIZE constant pls_integer := 1000;
  7. begin
  8. vc_sql:= 'select ename from t_emp where empno > :1';
  9. open cur_emp for vc_sql using 7900;
  10. loop
  11. fetch cur_emp bulk collect into enames limit CN_BATCH_SIZE;
  12. for i in 1..enames.count loop
  13. dbms_output.put_line(enames(i));
  14. end loop;
  15. exit when enames.count < CN_BATCH_SIZE;
  16. end loop;
  17. close cur_emp;
  18. end;
  19. /

2.4、Java代码里使用绑定变量

不用绑定变量的写法:

  1. String empno = '7369';
  2. String query_sql = 'select ename from t_emp where empno = 7369 ';
  3. stmt = con.prepareStatement( query_sql );
  4. stmt.executeQuery();

使用绑定变量的写法:

  1. String empno = 'xxxxx';
  2. String query_sql = 'select ename from t_emp where empno = ? '; //嵌入绑定变量
  3. stmt = con.prepareStatement( query_sql );
  4. stmt.setString(1, empno ); //为绑定变量赋值
  5. stmt.executeQuery();

批量绑定变量写法:

此例子来自《基于Oracle的SQL优化》一书:

  1. String vc_sql = 'update t_emp set sal = ? where empno = ?';
  2. pstmt = connection.prepareStatement(dml);
  3. pstmt.clearBatch();
  4. for (int i = 0; i < UPDATE_COUNT; ++ i) {
  5. pstmt.setInt(1, generateEmpno(i));
  6. pstms.setInt(2, generateSal(i));
  7. pstmt.addBatch();
  8. }
  9. pstmt.executeBatch();
  10. connection.commit();

Oracle SQL调优之绑定变量用法简介的更多相关文章

  1. Oracle性能调优之虚拟索引用法简介

    本博客记录一下Oracle虚拟索引的用法,虚拟索引是定义在数据字典中的伪索引,可以说是伪列,没有修改的索引字段的.虚拟索引的目的模拟索引,不会增加存储空间的使用,有了虚拟索引,开发者使用执行计划的时候 ...

  2. Oracle性能调优之物化视图用法简介

    目录 一.物化视图简介 二.实践:创建物化视图 一.物化视图简介 物化视图分类 物化视图分类,物化视图语法和as后面的sql分为: (1) 基于主键的物化视图(主键物化视图) (2)基于Rowid的物 ...

  3. Oracle SQL 调优健康检查脚本

    Oracle SQL 调优健康检查脚本 我们关注数据库系统的性能,进行数据库调优的主要工作就是进行SQL的优化.良好的数据架构设计.配合应用系统中间件和写一手漂亮的SQL,是未来系统上线后不出现致命性 ...

  4. Oracle SQL调优记录

    目录 一.前言 二.注意点 三.Oracle执行计划 四.调优记录 @ 一.前言 本博客只记录工作中的一次oracle sql调优记录,因为数据量过多导致的查询缓慢,一方面是因为业务太过繁杂,关联了太 ...

  5. Oracle SQL调优之分区表

    目录 一.分区表简介 二.分区表优势 三.分区表分类 3.1 范围分区 3.2 列表分区 3.3 散列分区 3.4 组合分区 四.分区相关操作 五.分区相关查询 附录:分区表索引失效的操作 一.分区表 ...

  6. Oracle SQL调优系列之SQL Monitor Report

    @ 目录 1.SQL Monitor简介 2.捕捉sql的前提 3.SQL Monitor 参数设置 4.SQL Monitor Report 4.1.SQL_ID获取 4.2.Text文本格式 4. ...

  7. Oracle SQL调优

    在多数情况下,Oracle使用索引t来更快地遍历表,优化器主要根据定义的索引来提高性能. 但是,如果在SQL语句的where子句中写的SQL代码不合理,就会造成优化器删去索引而使用全表扫描,一般就这种 ...

  8. Oracle SQL调优之表设计

    在看<收获,不止sql优化>一书,并做了笔记,本博客介绍一下一些和调优相关的表比如分区表.临时表.索引组织表.簇表以及表压缩技术 分区表使用与查询频繁而更新数据不频繁的情况,不过要记得加全 ...

  9. Oracle SQL 调优之 sqlhc

    SQL 执行慢,如何 快速准确的优化. sqlhc 就是其中最好工具之一 通过获得sql所有的执行计划,列出实际的性能的瓶颈点,列出 sql 所在的表上的行数,每一列的数据和分布,现有的索引,sql ...

随机推荐

  1. JS实现循环删除数组中元素的方法介绍

    这篇文章主要给大家介绍了关于Javascript循环删除数组中元素的几种方法,文中给出了详细的示例代码供大家参考学习,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧. 本文主要跟大家分享了 ...

  2. 导入spark2.3.3源码至intellij idea

    检查环境配置 maven环境 2.检查scala插件 没有的话可以到https://plugins.jetbrains.com/plugin/1347-scala/versions 下载与idea对应 ...

  3. Spring-boot:多模块打包

    <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot ...

  4. Docker跨服务器通信Overlay解决方案(下) Consul集群

    承接上文 本文基于上篇文章,详细的场景说明与分析在前篇随笔中业已记录,有兴趣可以移步 Docker跨服务器通信Overlay解决方案(上) Consul单实例 本文主旨 本文为Docker使用Cons ...

  5. Java中时间格式处理,指定N天/小时等之后的时间

    1)根据当前时间,获取具体的时刻的时间 N天前 M小时之前 可用 new Date().getTime() - 24 * 60 * 60 * 1000*N[N天之前]的方法来获取处理时间之后的具体的值 ...

  6. (五十)c#Winform自定义控件-滑块

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...

  7. Java基础之访问权限控制

    Java基础之访问权限控制 四种访问权限 Java中类与成员的访问权限共有四种,其中三种有访问权限修饰词:public,protected,private. Public:权限最大,允许所有类访问,但 ...

  8. python 用加法实现a,b两数相乘

    """思路:1.a * b = a + a + a + ... 2.a * b = n个a相加,只需求证b = n即可 3.用for 循环遍历即可,b就是range的最大 ...

  9. dmg文件转iso格式

    1. 简介 dmg是MAC苹果机上的压缩镜像文件,相当于在Windows上常见的iso文件. dmg格式在苹果机上可以直接运行加载,在Windows平台上需要先转换为iso格式. 2. 转换工具 本文 ...

  10. 【CF #541 D】 Gourmet choice

    link:https://codeforces.com/contest/1131 题意: 给定一些大小比较,输出排名. 思路: 这道题我用的是拓扑排序,又因为有等于号的存在,我用了并查集. 结束后这道 ...