搜索
首页数据库mysql教程Oracle11g新特性之动态变量窥视

欢迎进入Oracle社区论坛,与200万技术人员互动交流 >>进入 1. 11g之前的绑定变量窥视 我们都知道,为了能够让SQL语句共享执行计划,oracle始终都是强调在进行应用系统的设计时,必须使用绑定变量,也就是用一个变量来代替原来出现在SQL语句里的字面值。比如

欢迎进入Oracle社区论坛,与200万技术人员互动交流 >>进入

        1. 11g之前的绑定变量窥视

        我们都知道,为了能够让SQL语句共享执行计划,oracle始终都是强调在进行应用系统的设计时,必须使用绑定变量,也就是用一个变量来代替原来出现在SQL语句里的字面值。比如,对于下面三条SQL语句来说:

         select col1 from t where col2 = 1;
        select col1 from t where col2 = 2;
        select col1 from t where col2 = 3;

        我们可以看到,这三条SQL语句几乎一样,只有最后where条件里的字面值(分别是1、2、3)不同而已。但是如果写成这个样子,则oracle是不知道这三条SQL语句是一样的,仍然把它们当作三条完全不同的SQL语句,从而在shared pool里进行硬解析,并生成最终的执行计划。但是我们会发现,这三个执行计划可能都是一样的,因此后面两次生成执行计划的工作可能是完全不必要的,这在典型的OLTP环境中更是如此。由于解析本身属于CPU密集型操作,因此为了降低对CPU的消耗,oracle建议将这样的SQL写成:

         select col1 from t where col2 = :v1;

        然后,分别将1、2、3传递给v1,这样的话,只需要第一次传入1时进行解析即可。而后面执行2、3时,由于SQL文本本身没有变化,因此直接把执行计划拿来使用即可,不需要再次生成执行计划。

        但是,生成执行计划本身是基于概率的理论,在不访问具体表里的数据的前提下,根据你的where条件,来猜测返回的记录数大概是多少,从而判断应该采用怎样的访问路径。很明显,这是一定要参照具体的where条件里的值才能进行猜测的。这样就与节省CPU的初衷产生了矛盾,因为节省CPU的关键是使用绑定变量,你一旦使用了绑定变量,则oracle岂不是不知道你具体的字面值了吗?

        为了解决这一问题,oracle引入了绑定变量窥视。所谓绑定变量窥视,就是指oracle在第一次解析SQL语句的时候(也就是说该SQL第一次传入shared pool),会将你输入的绑定变量的值带入SQL语句里,从而参考你的字面值来猜测该SQL大概会返回多少条记录,从而得到优化的执行计划。然后,以后再次执行相同的SQL语句时,不再考虑你所输入的绑定变量的值,直接取出第一次生成的绑定变量。

        但是,很可惜的是,使用绑定变量从而共享游标与SQL优化是两个矛盾的目标。Oracle使用绑定变量的前提,是oracle认为大部分的列的数据都是分布比较均匀的。从而,使用第一次的绑定变量的值所得到的执行计划,大多数情况下都能适用于该绑定变量的其他的值。很明显,如果第一次传入的绑定变量的值恰好占整个数据量的百分比较高,从而导致全表扫描的执行计划。而后来传入的绑定变量的值都占整个数据量的百分比都很低,则应该走索引扫描会更好的,但是由于使用了绑定变量,从而oracle并不会再去看你的绑定变量的值,而是直接拿全表扫描的执行计划来用。这时,由于使用了绑定变量,虽然我们达到了游标共享,从而节省CPU的目的,但是SQL的执行计划却不够优化了。

        那么我们如何在绑定变量和SQL优化之间进行取舍呢?在OLTP应用中,由于并发性较高,CPU上的争用会比较严重,同时SQL本身执行时间较短,涉及到的数据量较少,解析所占的时间在整个SQL执行时间中占的比例较高,而花在I/O上的时间占的比例较低。因此尽管绑定变量会有SQL不够优化的问题,还是建议使用绑定变量。但是在DSS应用和数据仓库应用中,由于并发性较低,CPU上的争用较轻,同时SQL语句的执行时间都很长,而且主要时间花在等待I/O上,而解析占的比重较低,这时优化SQL执行计划的重要性就体现出来了。因此,建议不要使用绑定变量,而直接使用字面值。但是大多数的情况都是混合应用,既有OLTP又有数据仓库,这时就很难完美的解决该问题了。

        我们先来看一下11g之前的绑定变量窥视是如何工作的,以10g为例。

        我们先创建一个表,使得其含有的数据分布不均匀,并在该表上创建一个索引。

         hr@ora10g > create table t1 as select object_id as id,object_name from dba_objects;
        hr@ora10g > update t1 set id=1 where rownum        hr@ora10g > commit;
        hr@ora10g > create index idx_t1 on t1(id);

        这样,该表里id为的1记录有一万条,而id为其他值的记录都只有一条。从而,我们构建出一个分布不均匀的测试用表。然后,我们收集一下统计信息。注意,这里要收集直方图,为的是要让CBO知道id列上的数据分布不均匀。

         hr@ora10g> begin
        2 dbms_stats.gather_table_stats(
        3 user,
        4 't1',
        5 cascade => true,
        6 method_opt => 'for columns id size 254'
        7 );
        8 end;
        9 /

        我们找到表t1里最大的id,然后以该id作为第一个绑定变量传入,可以想象,该绑定变量将导致走索引。注意,我们这里设定的优化器目标为all_rows。

         hr@ora11g > select max(id) from t1;
        MAX(ID)
        ----------
        13871
        hr@ora10g> alter system flush shared_pool;
        hr@ora10g> var v_id number;
        hr@ora10g> var v_sql_id varchar2(20);
        hr@ora10g> exec :v_id := 13871;
        hr@ora10g> select * from t1 where id=:v_id;
        此处省略查询结果
        hr@ora10g > begin
        2 select sql_id into :v_sql_id from v$sql
        3 where sql_text like 'select * from t1 where id=:v_id%';
        4 end;
        5 /
        hr@ora10g > select * from table(dbms_xplan.display_cursor(:v_sql_id));
        PLAN_TABLE_OUTPUT
        --------------------------------------------------------------------------------
        SQL_ID djwq30cpbcz7k, child number 0
        -------------------------------------
        select * from t1 where id=:v_id
        Plan hash value: 50753647
        --------------------------------------------------------------------------------
        | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
        --------------------------------------------------------------------------------
        | 0 | SELECT STATEMENT | | | | 11 (100) |
        | 1 | TABLE ACCESS BY INDEX ROWID| T1 | 1365 | 28665| 11 (0) | 00:00:01
        |* 2 | INDEX RANGE SCAN | IDX_T1 | 1365 | | 3 (0) | 00:00:01
        --------------------------------------------------------------------------------
        ......
        hr@ora10g> exec :v_id := 1;
        hr@ora10g> select * from t1 where id=:v_id;
        此处省略查询结果
        hr@ora10g > begin
        2 select sql_id into :v_sql_id from v$sql
        3 where sql_text like 'select * from t1 where id=:v_id%';
        4 end;
        5 /
        hr@ora10g > select * from table(dbms_xplan.display_cursor(:v_sql_id));
        PLAN_TABLE_OUTPUT
        --------------------------------------------------------------------------------
        SQL_ID djwq30cpbcz7k, child number 0
        -------------------------------------
        select * from t1 where id=:v_id
        Plan hash value: 50753647
        --------------------------------------------------------------------------------
        | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
        --------------------------------------------------------------------------------
        | 0 | SELECT STATEMENT | | | | 11 (100) |
        | 1 | TABLE ACCESS BY INDEX ROWID| T1 | 1365 | 28665| 11 (0) | 00:00:01
        |* 2 | INDEX RANGE SCAN | IDX_T1 | 1365 | | 3 (0) | 00:00:01
        --------------------------------------------------------------------------------

        从上面结果可以看出,在为绑定变量传入第一个值为13871时,由于返回的记录条数较少,导致走索引扫描。当我们第二次传入绑定变量值1时,oracle不再生成新的执行计划,而直接拿索引扫描的执行路径来用。

        但是,如果先传入1的绑定变量值,然后再传入13871的绑定变量值时,会怎样?我们继续测试。

         hr@ora10g> alter system flush shared_pool;
        hr@ora10g> set autotrace traceonly exp stat;
        hr@ora10g> exec :v_id := 1;
        hr@ora10g> select * from t1 where id=:v_id;
        hr@ora10g > begin
        2 select sql_id into :v_sql_id from v$sql
        3 where sql_text like 'select * from t1 where id=:v_id%';
        4 end;
        5 /
        hr@ora10g > select * from table(dbms_xplan.display_cursor(:v_sql_id));
        PLAN_TABLE_OUTPUT
        --------------------------------------------------------------------------------
        SQL_ID djwq30cpbcz7k, child number 0
        -------------------------------------
        select * from t1 where id=:v_id
        Plan hash value: 3617692013
        --------------------------------------------------------------------------
        | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
        --------------------------------------------------------------------------
        | 0 | SELECT STATEMENT | | | | 13 (100)| |
        |* 1 | TABLE ACCESS FULL | T1 | 8738 | 179K | 13 (0) | 00:00:01 |
        --------------------------------------------------------------------------
        ......
        hr@ora10g > exec :v_id := 13871;
        hr@ora10g > select * from t1 where id=:v_id;
        hr@ora10g > begin
        2 select sql_id into :v_sql_id from v$sql
        3 where sql_text like 'select * from t1 where id=:v_id%';
        4 end;
        5 /
        hr@ora10g > select * from table(dbms_xplan.display_cursor(:v_sql_id));
        PLAN_TABLE_OUTPUT
        --------------------------------------------------------------------------------
        SQL_ID djwq30cpbcz7k, child number 0
        -------------------------------------
        select * from t1 where id=:v_id
        Plan hash value: 3617692013
        --------------------------------------------------------------------------
        | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
        --------------------------------------------------------------------------
        | 0 | SELECT STATEMENT | | | | 13 (100)| |
        |* 1 | TABLE ACCESS FULL | T1 | 8738 | 179K | 13 (0) | 00:00:01 |
        --------------------------------------------------------------------------

        很明显,先传入1的绑定变量时将导致生成的执行计划走全表扫描。后面传入的13871的绑定变量的最佳执行路径应该是索引扫描,但是由于CBO并不知道这一点,而是直接拿第一次生成的执行计划来用了,于是也走全表扫描了。

[1] [2] 

Oracle11g新特性之动态变量窥视

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
PHP 8.3发布:新特性一览PHP 8.3发布:新特性一览Nov 27, 2023 pm 12:52 PM

PHP8.3发布:新特性一览随着技术的不断发展和需求的不断变化,编程语言也在不断更新和改进。作为一种广泛应用于网络开发的脚本语言,PHP一直在不断进步,为开发者提供更强大和高效的工具。最近发布的PHP8.3版本带来了许多期待已久的新特性和改进,下面让我们来看一下这些新特性的一览。非空属性的初始化在过去的PHP版本中,如果一个类的属性没有被明确赋值,它的值

学习PHP8的新特性,深入理解最新技术的指南学习PHP8的新特性,深入理解最新技术的指南Dec 23, 2023 pm 01:16 PM

深入解析PHP8的新特性,助您掌握最新技术随着时间的推移,PHP编程语言一直在不断演进和改进。最近发布的PHP8版本为开发者提供了许多令人兴奋的新特性和改进,为我们的开发工作带来了更多便利和效率。在本文中,我们将深入解析PHP8的新特性,并提供具体的代码示例,旨在帮助您更好地掌握这些最新的技术。JIT编译器PHP8引入了JIT(Just-In-Time)编

PHP8.1引入的新的Redis扩展PHP8.1引入的新的Redis扩展Jul 07, 2023 pm 09:41 PM

PHP8.1引入的新的Redis扩展随着互联网的快速发展,大量的数据需要进行存储和处理。为了提高数据处理的效率和性能,缓存成为了一个不可或缺的部分。而在PHP开发中,Redis作为一种高性能的键值对存储系统,被广泛应用于缓存和数据存储的场景。为了进一步提升Redis在PHP中的使用体验,PHP8.1引入了新的Redis扩展,本文将介绍这一扩展的新增功能,并给

CSS3的新特性一览:如何使用CSS3实现过渡效果CSS3的新特性一览:如何使用CSS3实现过渡效果Sep 09, 2023 am 11:27 AM

CSS3的新特性一览:如何使用CSS3实现过渡效果CSS3作为CSS的最新版本,在众多新特性中,最有趣和实用的应该是过渡效果(transition)。过渡效果可以让我们的页面在交互时更加平滑、漂亮,给用户带来良好的视觉体验。本文将介绍CSS3过渡效果的基本用法,并附带相应的代码示例。transition-property属性:指定需要过渡的CSS属性过渡效果

php8有什么新特性php8有什么新特性Sep 25, 2023 pm 01:34 PM

php8新特性有JIT 编译器、类型推导、命名参数、联合类型、属性、错误处理改进、异步编程支持、新的标准库函数和匿名类的扩展等。详细介绍:1、JIT编译器,PHP8引入了JIT编译器,这是一个重要的性能改进,JIT编译器可以对一些高频执行的代码进行实时编译和优化,从而提高运行速度;2、类型推导,PHP8引入了类型推导功能,允许开发者在声明变量时自动推导出变量的类型等等。

CSS3的新特性一览:如何使用CSS3实现水平居中布局CSS3的新特性一览:如何使用CSS3实现水平居中布局Sep 09, 2023 pm 04:09 PM

CSS3的新特性一览:如何使用CSS3实现水平居中布局在网页设计和布局中,水平居中布局是一项常见的需求。过去,我们经常使用复杂的JavaScript或CSS技巧实现此目的。然而,CSS3引入了一些新的特性,使得水平居中布局更加简单和灵活。本文将介绍一些CSS3的新特性,并提供一些代码示例,演示如何使用CSS3实现水平居中布局。一、使用flexbox布局fle

go语言有什么新特性go语言有什么新特性Aug 24, 2023 pm 01:36 PM

go语言的新特性有:1、Go模块,用于管理Go语言项目的依赖关系;2、错误处理,增加了一个新的错误类型error,使得错误处理更加灵活和简洁;3、上下文包,用于在goroutine之间传递请求范围的值;4、嵌入,即一个结构体可以嵌入到另一个结构体中;5、同步包,更好地控制goroutine之间的同步和通信;6、错误值,更好地区分不同类型的错误;7、泛型,让开发者编写更灵活。

jdk8新特性jdk8新特性Aug 11, 2023 am 10:51 AM

jdk8新特性:1、Lambda表达式;2、Stream API;3、函数式接口;4、默认方法;5、方法引用;6、新的日期和时间API;7、并发增强;8、其他改进等等。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前By尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
4 周前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

VSCode Windows 64位 下载

VSCode Windows 64位 下载

微软推出的免费、功能强大的一款IDE编辑器

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具