数据库环境
LEO1@LEO1> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
TNS for Linux: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production
一 用示例说明绑定变量的应用领域是OLTP而不是OLAP
变量绑定:这是一个老生常谈的话题,我所理解的绑定就是执行计划的绑定,我所理解的变量就是谓词替换的变量。
变量绑定机制:要说机制不得不说一下SQL执行的过程,三部曲:解析 –> 执行 -> 取操作,而绑定变量就发生在解析这一步,而解析又分成硬解析和软解析。
硬解析:当一条SQL语句第一次执行时,首先生成执行计划,并把这个执行计划存放到shared_pool的library cache中,这个过程叫做硬解析。
软解析:如果SQL语句已经被硬解析过了,那么可以直接从library cache中抽取现成的执行计划来重用,这个过程叫做软解析,目的减少生成执行计划这方面的资源消耗。为什么这么说呢,硬解析会消耗一些系统资源,尤其是CPU的资源,从而影响系统的效率,如果能把这方面的影响消除,那么对系统当然是多多益善了,哈 多侃了几句。
SQL详细执行过程:当oracle接收到一条sql语句时,首先会把这条sql语句字符做成哈希值,然后到library cache中寻找是否有和这个哈希值相匹配的sql存在,如果有就直接使用这个sql的执行计划去执行当前的sql语句,最后将结果返回给用户。如果没有找到相同的哈希值,oracle会认为这是一条新的sql,将会重新生成执行计划来执行(在这个过程中先要检查语法分析和语义分析),最后将结果返回给用户。
实验
下面我们演示一下绑定变量和非绑定变量在资源消耗上的差异
LEO1@LEO1> drop table leo1 purge; 清理环境
Table dropped.
LEO1@LEO1> drop table leo2 purge;
Table dropped.
LEO1@LEO1> create table leo1 as select * from dba_objects; 创建leo1
Table created.
LEO1@LEO1> create table leo2 as select * from dba_objects; 创建leo2
Table created.
LEO1@LEO1> alter session set tracefile_identifier='bind_variable'; 设置trace文件标识
Session altered.
LEO1@LEO1> alter session set sql_trace=true; 启动trace功能,追踪sql资源消耗情况
Session altered.
LEO1@LEO1> begin
for i in 1..100 loop
execute immediate 'select * from leo1 where object_id=:i' using i;
end loop;
end;
/
PL/SQL procedure successfully completed.
我们对一条sql执行了100次并采用了绑定变量技术,oracle对这条sql只有一次硬解析,没有软解析,反复执行100次。
LEO1@LEO1> alter session set sql_trace=false; 关闭trace功能
Session altered.
LEO1@LEO1> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select * from leo1 where %';
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
-------------------------------------------------- ----------- -------------------------- ----------- ---------- ------------------
select * from leo1 where object_id=:i 1 1 100
SQL_TEXT:我们跟踪的sql语句
PARSE_CALLS:硬解析+软解析次数 1次 只有硬解析没有软解析
LOADS:硬解析次数 1次
EXECUTIONS:执行次数 100次
虽说值隐藏在变量中,但在解析环节oracle认为是一样的
[oracle@leonarding1 trace]$ tkprof LEO1_ora_16433_bind_variable.trc bind_variable.txt sys=no
TKPROF: Release 11.2.0.1.0 - Development on Fri Feb 1 13:18:08 2013
Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
使用tkprof工具过滤和汇总trace文件的,sys=no 不输出sys用户递归语句,默认yes,实际上设置成no更具有可读性
--------- 下面是bind_variable.txt文件信息
********************************************************************************
SQL ID: 0b74y9utb0b6r #这就是SQL语句字符的哈希值
Plan Hash: 2716644435
select *
from
leo1 where object_id=:i
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 100 0.01 0.01 0 1 0 0
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 101 0.01 0.01 0 1 0 0
Misses in library cache during parse: 1 只有1次硬解析,反复执行100次
Optimizer mode: ALL_ROWS
Parsing user id: 85 (recursive depth: 1)
Rows Row Source Operation
------- ---------------------------------------------------
0 TABLE ACCESS FULL LEO1 (cr=0 pr=0 pw=0 time=0 us cost=288 size=2484 card=12)
********************************************************************************
下面是一个非绑定变量的sql执行情况
LEO1@LEO1> alter session set sql_trace=true; 启动trace功能
Session altered.
LEO1@LEO1> begin
for i in 1..100 loop
execute immediate 'select * from leo2 where object_id='||i;
end loop;
end;
/
PL/SQL procedure successfully completed.
我们对一条sql执行了100次没有采用绑定变量技术,oracle对这条sql要硬解析100次,执行100次,资源严重被sql解析所消耗,系统显得缓慢不堪。
LEO1@LEO1> alter session set sql_trace=false; 关闭trace功能
Session altered.
LEO1@LEO1> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select * from leo2 where %' order by 1;
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
-------------------------------------------------- ----------- ---------- ----------
select * from leo2 where object_id=1 1 1 1
select * from leo2 where object_id=10 1 1 1
select * from leo2 where object_id=100 1 1 1
select * from leo2 where object_id=11 1 1 1
select * from leo2 where object_id=12 1 1 1
select * from leo2 where object_id=13 1 1 1
select * from leo2 where object_id=14 1 1 1
select * from leo2 where object_id=15 1 1 1
select * from leo2 where object_id=16 1 1 1
select * from leo2 where object_id=17 1 1 1
select * from leo2 where object_id=18 1 1 1
select * from leo2 where object_id=19 1 1 1
select * from leo2 where object_id=2 1 1 1
select * from leo2 where object_id=20 1 1 1
select * from leo2 where object_id=21 1 1 1
select * from leo2 where object_id=22 1 1 1
select * from leo2 where object_id=23 1 1 1
select * from leo2 where object_id=24 1 1 1
select * from leo2 where object_id=25 1 1 1
select * from leo2 where object_id=26 1 1 1
select * from leo2 where object_id=27 1 1 1
select * from leo2 where object_id=28 1 1 1
select * from leo2 where object_id=29 1 1 1
select * from leo2 where object_id=3 1 1 1
select * from leo2 where object_id=30 1 1 1
select * from leo2 where object_id=31 1 1 1
select * from leo2 where object_id=32 1 1 1
select * from leo2 where object_id=33 1 1 1
select * from leo2 where object_id=34 1 1 1
select * from leo2 where object_id=35 1 1 1
select * from leo2 where object_id=36 1 1 1
select * from leo2 where object_id=37 1 1 1
select * from leo2 where object_id=38 1 1 1
select * from leo2 where object_id=39 1 1 1
select * from leo2 where object_id=4 1 1 1
select * from leo2 where object_id=40 1 1 1
select * from leo2 where object_id=41 1 1 1
select * from leo2 where object_id=42 1 1 1
select * from leo2 where object_id=43 1 1 1
select * from leo2 where object_id=44 1 1 1
select * from leo2 where object_id=45 1 1 1
select * from leo2 where object_id=46 1 1 1
select * from leo2 where object_id=47 1 1 1
select * from leo2 where object_id=48 1 1 1
select * from leo2 where object_id=49 1 1 1
select * from leo2 where object_id=5 1 1 1
select * from leo2 where object_id=50 1 1 1
select * from leo2 where object_id=51 1 1 1
select * from leo2 where object_id=52 1 1 1
select * from leo2 where object_id=53 1 1 1
select * from leo2 where object_id=54 1 1 1
select * from leo2 where object_id=55 1 1 1
select * from leo2 where object_id=56 1 1 1
select * from leo2 where object_id=57 1 1 1
select * from leo2 where object_id=58 1 1 1
select * from leo2 where object_id=59 1 1 1
select * from leo2 where object_id=6 1 1 1
select * from leo2 where object_id=60 1 1 1
select * from leo2 where object_id=61 1 1 1
select * from leo2 where object_id=62 1 1 1
select * from leo2 where object_id=63 1 1 1
select * from leo2 where object_id=64 1 1 1
select * from leo2 where object_id=65 1 1 1
select * from leo2 where object_id=66 1 1 1
select * from leo2 where object_id=67 1 1 1
select * from leo2 where object_id=68 1 1 1
select * from leo2 where object_id=69 1 1 1
select * from leo2 where object_id=7 1 1 1
select * from leo2 where object_id=70 1 1 1
select * from leo2 where object_id=71 1 1 1
select * from leo2 where object_id=72 1 1 1
select * from leo2 where object_id=73 1 1 1
select * from leo2 where object_id=74 1 1 1
select * from leo2 where object_id=75 1 1 1
select * from leo2 where object_id=76 1 1 1
select * from leo2 where object_id=77 1 1 1
select * from leo2 where object_id=78 1 1 1
select * from leo2 where object_id=79 1 1 1
select * from leo2 where object_id=8 1 1 1
select * from leo2 where object_id=80 1 1 1
select * from leo2 where object_id=81 1 1 1
select * from leo2 where object_id=82 1 1 1
select * from leo2 where object_id=83 1 1 1
select * from leo2 where object_id=84 1 1 1
select * from leo2 where object_id=85 1 1 1
select * from leo2 where object_id=86 1 1 1
select * from leo2 where object_id=87 1 1 1
select * from leo2 where object_id=88 1 1 1
select * from leo2 where object_id=89 1 1 1
select * from leo2 where object_id=9 1 1 1
select * from leo2 where object_id=90 1 1 1
select * from leo2 where object_id=91 1 1 1
select * from leo2 where object_id=92 1 1 1
select * from leo2 where object_id=93 1 1 1
select * from leo2 where object_id=94 1 1 1
select * from leo2 where object_id=95 1 1 1
select * from leo2 where object_id=96 1 1 1
select * from leo2 where object_id=97 1 1 1
select * from leo2 where object_id=98 1 1 1
select * from leo2 where object_id=99 1 1 1
100 rows selected.
我们从动态性能视图上可以看出oracle每执行一次sql,都要先硬解析1次之后在执行。这种没有使用绑定变量技术在硬解析消耗上就比使用绑定变量技术多损耗100倍,如果执行的次数上万 上亿对系统性能的影响可想而知。
--------- 我们来看看trace文件的内容
[oracle@leonarding1 trace]$ tkprof LEO1_ora_16433_bind_variable.trc bind_variable.txt sys=no
TKPROF: Release 11.2.0.1.0 - Development on Fri Feb 1 13:49:52 2013
Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
********************************************************************************
SQL ID: 22r47f3t6w0td
Plan Hash: 2258638698
select *
from
leo2 where object_id=1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 1 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.00 0.00 0 1 0 0
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 85 (recursive depth: 1)
Rows Row Source Operation
------- ---------------------------------------------------
0 TABLE ACCESS FULL LEO2 (cr=0 pr=0 pw=0 time=0 us cost=288 size=2484 card=12)
********************************************************************************
SQL ID: 9nb3n54fy0z8m
Plan Hash: 2258638698
select *
from
leo2 where object_id=2
********************************************************************************
SQL ID: 8mc705qymd7qs
Plan Hash: 2258638698
select *
from
leo2 where object_id=3
如上所示每个sql语句的SQL_ID都是不一样的,都是相对独立的,因此每执行1次就要解析1次,两种情况对比结果显示,绑定变量要比没有绑定变量消耗的资源少的少,sql执行的次数越多,这种效果越明显。所以我们说绑定变量本质就是用一个变量来代替谓词常量,让oracle只需要硬解析一次,后续sql都直接使用之前执行计划来执行,这样就省却了很消耗资源的硬解析过程
下面讨论绑定变量为什么适合于OLTP而不是OLAP
OLTP
1.适合OLTP系统架构
2.SQL简单非常相似,结果集非常小,例如 只有谓词部分不同,余下部分全部相同的SQL语句,这种情况下执行计划都是一样的,在执行计划几乎不变的情况下,oracle使用变量来代替谓词常量,使用同一个执行计划是非常合理的
3.SQL重复率很高,或者只有谓词条件不同而已
4.DML操作频繁
5.SQL语句执行条数多,条数越多减少硬解析越有意义
6.基于主键做查询,还有等值查询,唯一性查询,这类查询相对适合绑定变量
select * from leonarding where id=:leo;
OLAP
1.不适合OLAP系统架构
2.SQL的执行计划多变,会因为值的不同导致执行计划的不同,可能第一次执行是一种执行计划,第二次执行是另一种执行计划,所以不适合进行绑定变量操作,会让oracle盲目浪费大量资源消耗,SQL语句即使只有谓词条件不同,oracle应然可能采取不同的执行计划。
3.SQL重复率较低,大部分都是批量加载批量检索的操作
4.数据聚合操作频繁
5.SQL语句执行条数少,SQL硬解析对系统性能影响较小,绑定没有意义
6.分区表相对不太适合绑定变量技术
©著作权归作者所有:来自51CTO博客作者leonarding1的原创作品,如需转载,请注明出处,否则将追究法律责任
绑定变量硬解析bind peeking性能优化
共同学习,写下你的评论
评论加载中...
作者其他优质文章