继续贴出 Troubleshooting Oracle Performance 一书第二章《关键概念》的翻译稿的部分节录。昨天贴出第一章的部分内容,收到不少朋友的反馈,坦诚的讲,第一章多半是通用知识,和 DB 相关的信息并不是很多,这次再看看第二章的(借口归借口,问题还是要改正)。必须要说明的是,此书翻译并非兄弟我一人之力。译者包括:童家旺、胡怡文、冯大辉(出版顺序),还有海外华人朱一和青年才俊张磊两位的劳动成果。如果留言有问题,请在 Twitter 上给我反馈也可: @Fenng
(此书中文名字还未敲定)
绑定变量
绑定变量通过两种方式来影响应用。第一,从开发的角度看,它使得开发或者变得简单,或者是变得更加困难(或更精确地讲,需要更多或更少地编码)。既然这样,具体的效果就取决于用来执行SQL语句的应用程序接口(Application Programming Interface, API)。例如,如果是使用PL/SQL来编码,使用绑定变量来执行就会更加简单。另一方面,如果是使用JDBC(Java Data Base Connectivity)来开发,不使用绑定变量来执行SQL语句则会更加简单。第二,从性能的角度看,绑定变量既有优势也有劣势。
注意:你将会在下面的内容中看到一些执行计划。第6章将会介绍如何获取并解释执行计划。如果有什么不清楚的话,可以考虑稍后返回本章。
2.5.1 优势
绑定变量的优势是可以在库缓存中共享游标,这样就可以避免硬解析以及与之相关的额外开销。下面内容是运行脚本bind_variables.sql的结果,它展示了三个INSERT语句由于使用绑定变量而共享了库缓存中的同一个游标的情形。
SQL代码, 略.
可是,也有一些情况下,即使使用绑定变量也会产生多个子游标。下面的例子就展示了这种情况。注意,INSERT语句与前面例子中的完全一样。只有对应的VARCHAR2变量的最大长度发生了变化(从32变成33了)。
SQL代码, 略.
之所以会创建新的子游标(子游标1),是因为相对于最初的3个INSERT语句来讲,第4个INSERT语句的执行环境发生了变化。 这个不匹配可以通过查询视图 v$sql_shared_cursor 来得到确认,是绑定变量的原因。
SQL代码, 略.
这是由于数据库引擎应用了绑定变量分级(graduation)。这个功能的目的是为了最小化子游标的数量,它是根据绑定变量的长短将绑定变量(各个大小不同)分为四个级别。在32个字节以内被分在第一个级别,33到128个字节的被分在第二个级别,129到2000个字节的被分在第三个级别,其余的大于2000个字节的被分在第四个级别。NUMBER类型的绑定变量被分在它的最大长度22个字节上的级别上。从下面的例子可以看到,视图v$sql_bind_metadata显示了级别的最大长度。注意,即使在子游标1的变量长度只有33的时候,也是使用最大长度为128的级别。
SQL代码, 略.
系统不要求每次生成子游标的时候都生成一个新的执行计划。新的执行计划是否与另一个子游标使用的执行计划一致,也依赖于绑定变量的值。这将在下面的内容中进行介绍。
2.5.2 劣势
在WHERE从句中使用绑定变量的缺点是会有一些至关重要的信息对查询优化器不可见。事实上,对查询优化器来讲,使用直接文本要比使用绑定变量来的更好。使用直接文本可以提高成本估算的准确性。当检查一个值是否在可用数值范围以外(也就是,小于存储在这个字段的最小值,或者大于最大值)或者是否利用到直方图(histogram)时,就更是这样了。为了展示的需要,我们准备了一个含有1000条记录的表,它的字段id的值在1(最小值)到1000(最大值)之间。
SQL代码, 略.
如果一个用户查询id小于990的所有记录,查询优化器知道(根据对象的统计信息)有差不多99%的记录被筛选。因此,它会选择使用基于全表扫描的执行计划。同时请注意,估算出的基数(执行计划中Rows字段的信息)与查询语句实际返回的记录数是否相符。
SQL代码, 略.
当另外一个用户查询id小于10的所有记录时,查询优化器知道只有大约1%的记录会被选中。因此,它会选择使用基于索引扫描的执行计划。在这个例子中,也请注意估算的准确与否。
SQL代码, 略.
只要是使用到绑定变量,查询优化器都会忽略它们的具体值。从而,前面例子中的准确的估算就不太可能会出现。为了解决这个问题,Oracle9i中引入了一个被称为绑定变量窥测(bind variable peeking)的功能。
警告:绑定变量窥测不支持随Oracle9i一起发布的JDBC 瘦驱动(JDBC thin driver)。这个限制在Metalink的注解273635.1中有记载。
绑定变量窥测的概念是比较简单的。在物理优化阶段,查询优化器会窥测绑定变量的值,将它作为文本来使用。这种方法的问题是它生成的执行计划会依赖第一次生成执行计划时所提供的值。下面这个基于脚本bind_variable_peeking.sql的例子展示了这种情形。注意,第一次优化是使用值990来执行的。结果,查询优化器就选择了全表扫描。由于游标是共享的,因此是这个选择影响了第二次使用10作为条件的查询语句。
当然,如同在下面的例子中那样,如果第一个执行计划替换成使用值10来执行,查询优化器就会选择一个基于索引扫描的执行计划-然后,就会再一次发生这两条查询语句上。注意,为了避免共享前面例子中的游标,这些语句是使用小写字母来写的。
有必要强调,只要游标还保存在库缓存中并且可以被共享,就可以被重用。不管与它相关的执行计划的效率如何,这种事情都会发生。
为了解决这个问题,Oracle11g中引入了一个称为扩展的游标共享(extended cursor sharing,也称为适应性游标共享,adaptive cursor sharing)的新功能。它的目的是在重用一个已经存在的但是会导致执行效率低下的游标时能够自动进行识别。通过查看前面例子中使用的SQL语句在v$sql中的内容,可用来帮助我们理解这个特性是如何工作的。要到Oracle11g中v$sql视图中才有下面这些字段:
- 是否绑定敏感(is_bind_sensitive):不仅指出是否使用绑定变量窥测来生成执行计划,而且指出这个执行计划是否依赖于窥测到的值。如果是,这个字段会被设置为Y,否则会被设置为N。
- 是否绑定可知(is_bind_aware):表明游标是否使用了扩展的游标共享。如果是,这个字段会被设置为Y,如果不是,这个字段会被设置为N。如果是设置为N,这个游标将被废弃,不再可用。
- 是否可共享(is_shareable):表明游标能否被共享。如果可以,这个字段会被设置为Y,否则,会被设置为N。如果被设置为N,这个游标将被废弃,不再可用。
在下面的例子中,游标是可共享的并且是绑定变量敏感的,但是没有使用扩展的游标共享:
SQL代码, 略.
当游标对这个绑定变量赋不同的值执行多次以后,有趣的事情发生了。在使用值10和990执行了几次以后,视图v$sql提供的信息发生了变化。注意,0号游标不再可共享,并且产生了两个新的使用了扩展的游标共享的子游标。
查看与这个游标关联的执行计划,你可能会发现,其中一个新的子游标会使用基于全表扫描的执行计划,而同时另一个会使用基于索引扫描的执行计划:
SQL代码, 略.
有以下几个新的动态性能视图可用来进一步分析生成这两个游标的原因:v$sql_cs_statistics、 v$sql_cs_selectivity和v$sql_cs_histogram。第一个视图说明是否使用了窥测(peeking)以及对应于每个游标的相关执行统计信息。根据下面的输出,基本可以确认,对于同一个执行语句,游标1处理的记录数高于游标2处理的记录数。因此,查询优化器在一种情况下选择了全表扫描,而在另一种情况下却选择了索引扫描。
SQL代码, 略.
视图v$sql_cs_selectivity显示与每个游标的每个选择条件相关的选择性范围。事实上,数据库引擎不会为每一个绑定变量值创建一个新的游标。而是将具有同样选择性的并有可能导致生成同一个执行计划的绑定变量值组合在一起(以生成一个新的游标)。
SQL代码, 略.
总的来讲,为了提高执查询优化器生成高效的执行计划的可能性,最好不要使用绑定变量。绑定变量有时候可能有用。遗憾的是,生成的执行计划是否高效只能看运气如何。唯一的例外是,Oracle数据库11g中的新的扩展的游标共享会自动识别这个问题。
2.5.3 最佳实践
使用任何特性都需要权衡利弊得失。有些情况下,这是比较容易决定的。例如,在不涉及到Where从句(如普通的插入语句)的时候,就没理由不使用绑定变量。另一方面,在柱状图信息对查询优化器有很大影响的情况下,最好不要使用绑定变量。否则,可能会在进行绑定变量窥视的时候遇到较大负面风险。不过,还有以下两个关键案例可供参考:
- SQL语句处理少量数据:每逢被处理的数据量很少的时候,解析时间有可能会接近甚至高于执行时间。在这种情况下,使用绑定变量就经常是一种较优选择。特别是在SQL语句将会频繁执行的情况下。数据资料系统(data entry system,常常也称之为OLTP系统)是典型的使用这种SQL语句的系统。
- SQL语句处理大量数据:在大量数据被处理的情况下,解析时间常常比执行时间要少好几个数量级。在这种情况下,使用绑定变量对于总的响应时间(response time)几乎没有影响,但是它也会提高查询优化器生成低效的执行计划的风险。因此不要使用绑定变量。批量任务处理(batch job)、报表生成或者运用OLAP工具的数据仓库(data warehouse)环境是使用这种SQL的典型场景。
--EOF--
分享到:
相关推荐
05 js练习之二级联动 06 jquery以及jquery对象介绍 07 jquery选择器 08 jquery的查找筛选器 09 jquery练习之左侧菜单 第44章 01 jquery属性操作之html,text,val方法 02 jquery循环方法和attr,prop方法 03 jquery...
#### 二、Window对象 Window对象是浏览器窗口的一个表示,并且是所有JavaScript全局对象、函数以及变量的容器。 1. **常用属性**: - `window`包含了一系列重要的子对象:如`document`、`history`、`location`、`...
第1章(\第1章) 查看1.2.htm中noscript显示效果的方法如下: 1.将该实例复制到C:\Inetpub\wwwroot下; 2.选择浏览器的“工具”-“安全”-“本地Intranet”-“自定义级别”-“活动脚本”中选用“禁用”单选框 ...
第二部分用户界面313 第9章先进的窗体和对话框313 9.1窗体的标准用法313 9.1.1窗体作为对象313 9.1.2可复用窗体317 9.1.3窗体作为对象浏览器321 9.1.4动态控件创建324 9.1.5数据驱动窗体328 9.2 MDI窗体333 9.2.1 ...
第二部分用户界面313 第9章先进的窗体和对话框313 9.1窗体的标准用法313 9.1.1窗体作为对象313 9.1.2可复用窗体317 9.1.3窗体作为对象浏览器321 9.1.4动态控件创建324 9.1.5数据驱动窗体328 9.2 MDI窗体333 9.2.1 ...
第1章(\第1章) 查看1.2.htm中noscript显示效果的方法如下: 1.将该实例复制到C:\Inetpub\wwwroot下; 2.选择浏览器的“工具”-“安全”-“本地Intranet”-“自定义级别”-“活动脚本”中选用“禁用”单选框 ...
### 第二章:画面档(FORM)组成 #### 画面档(FORM)的组成 - **SCHEMA Section**:定义数据模型,包括字段名和数据类型等信息。 - **ACTION DEFAULTS Section**:定义默认行为,如按钮点击时的操作。 - **TOP ...
变量和`let`表达式章节介绍了局部作用域的概念,`let`允许在特定范围内绑定变量并执行代码块。`lambda`表达式是函数定义的关键,它允许创建匿名函数,增强了代码的灵活性。最后,`top-level definitions`即顶级定义...
### 第二十章:选择 **20.1 选择机制** - **Selection Mechanism**:介绍Tk中的选择机制,包括文本选择和剪贴板操作。 以上章节涵盖了Tcl/TK经典教程的主要内容,从基础概念到高级特性都有涉及。通过学习这些章节,...
2.2.2 一对一联系 2.2.3 一对多联系 2.2.4 多对多联系 2.3 规范化准则 2.3.1 范式 2.3.2 第一范式 2.3.3 第二范式 2.3.4 第三范式 2.3.5 第四范式 2.4.小结第2篇 数据库管理篇第3章 数据库的相关操作 3.1 创建数据库...
第1章 窗体与界面设计 1 1.1 菜单应用实例 2 实例001 带历史信息的菜单 2 实例002 菜单动态合并 3 实例003 像开始菜单一样漂亮的菜单 4 实例004 任务栏托盘菜单 4 实例005 可以拉伸的菜单界面 5 实例006 ...
C#编程经验技巧宝典源代码,目录如下: 第1章 开发环境 1 <br>1.1 Visual Studio开发环境安装与配置 2 <br>0001 安装Visual Studio 2005开发环境须知 2 <br>0002 配置合适的Visual Studio 2005...
第18章 程序应用控制 483 18.1 提取信息 484 0795 判断驱动器类型并获取其属性 484 0796 如何得到本地机器的IP 484 0797 如何得到本地运行的EXE的路径 485 0798 得到计算机所有正在运行的进程 485 0799...
第1章 C#语言基础 1 1.1 常用概念、关键字及基础类 1 1.1.1 abstract关键字——抽象 1 1.1.2 as操作符——引用类型转换 3 1.1.3 base关键字——从派生类中访问基类的成员 3 1.1.4 变量——存储特定类型的数据 4 ...
+-- 第二章 图形输出 |------ 2.1 和GUI有关的各种对象 |------ 2.2 在窗口中输出文字 |------ 2.3 使用点,刷子,笔进行绘图 |------ 2.4 在窗口中绘制设备相关位图,图标,设备无关位图 |------ 2.5 使用各种映射...