楼主: hhwytfliq

[讨论] 最新使用动态SQL进行变量绑定 分析

[复制链接]
论坛徽章:
1
ITPUB9周年纪念徽章
日期:2010-10-08 09:28:52
11#
发表于 2010-9-24 14:03 | 只看该作者
在这里和大家说一下,这种方法不行,因大数据量使用全表扫描的时候sys_context与直接变量绑定的差异很大,因为sys_context其实也相当于一个函数,从一个内存表中取数据
类似于

  1.     SELECT *  from dba_objects WHERE object_name = (SELECT object_name
  2.            from dba_objects WHERE object_name = 'UNDO$');
复制代码

这句SQL的执行的时间并不是简单的子查询的用时加上外层查询用时,上面耗时0.2,下面的耗时0.015


  1.    
  2.           SELECT *
  3.            from dba_objects WHERE object_name = 'UNDO$';

复制代码

我也不是很明白为什么会产生的这样的问题,如果有人明白请告诉我 一下

[ 本帖最后由 hponiang 于 2010-9-24 14:04 编辑 ]

使用道具 举报

回复
论坛徽章:
86
2015中国数据库技术大会纪念徽章
日期:2015-04-24 16:04:24马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11优秀写手
日期:2013-12-18 09:29:11日产
日期:2013-10-17 08:44:39马自达
日期:2013-08-26 16:28:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-23 16:55:51马上有房
日期:2014-02-19 11:55:14
12#
发表于 2010-9-25 08:52 | 只看该作者
原帖由 hponiang 于 2010-9-21 16:32 发表
比如我使用一个存储过程A ,有五个参数,当参数为-1的时候代表参数不生效,当不是-1的时候要使用参数,你用动态SQl使用你那种方法怎么搞,要麻烦死了


对于一些不重要的,不影响执行计划的,可以用decode等函数来处理

当然,楼主的方法也是解决这个问题的很好的思路

使用道具 举报

回复
论坛徽章:
86
2015中国数据库技术大会纪念徽章
日期:2015-04-24 16:04:24马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11优秀写手
日期:2013-12-18 09:29:11日产
日期:2013-10-17 08:44:39马自达
日期:2013-08-26 16:28:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-23 16:55:51马上有房
日期:2014-02-19 11:55:14
13#
发表于 2010-9-25 08:59 | 只看该作者
原帖由 hponiang 于 2010-9-24 14:03 发表
在这里和大家说一下,这种方法不行,因大数据量使用全表扫描的时候sys_context与直接变量绑定的差异很大,因为sys_context其实也相当于一个函数,从一个内存表中取数据
类似于

    SELECT *  from dba_objects WHERE object_name = (SELECT object_name
           from dba_objects WHERE object_name = 'UNDO$');

这句SQL的执行的时间并不是简单的子查询的用时加上外层查询用时,上面耗时0.2,下面的耗时0.015


   
          SELECT *
           from dba_objects WHERE object_name = 'UNDO$';


我也不是很明白为什么会产生的这样的问题,如果有人明白请告诉我 一下


可能有影响,但影响不会很大

你的这两个例子,肯定差异很大。不要用dba_objects,ctas一个表,看看执行计划就清楚了。

使用道具 举报

回复
论坛徽章:
1
ITPUB9周年纪念徽章
日期:2010-10-08 09:28:52
14#
发表于 2010-9-27 10:31 | 只看该作者
我使用其它的表也是有这个问题的,如果你们那里有数据量比较,并且选择性很好的列,你们可以按我说的测试一下,这个问题很令人费解

使用道具 举报

回复
论坛徽章:
1
ITPUB9周年纪念徽章
日期:2010-10-08 09:28:52
15#
发表于 2010-9-27 13:14 | 只看该作者
我想了一个相当土的办法


  1. nb_sql :='select * from customer where 1=1'
  2. if v_id <> null then
  3.   nb_sql:=nb_sql||' custid=:1';
  4.   nb_param:= nb_param||','||to_char(v_id);
  5. end if;
  6. 再在后面把nb_param按逗号拆开成一个数组,根据数组的count
  7. case count when
  8. 1
  9. then exec.... using param(1)
  10. when 2
  11. then exec.... using param(1),param(2);

复制代码

你不要说我雷,你有更好的办法么

使用道具 举报

回复
论坛徽章:
1
ITPUB9周年纪念徽章
日期:2010-10-08 09:28:52
16#
发表于 2010-9-28 13:55 | 只看该作者
你有更好的办法么

使用道具 举报

回复
论坛徽章:
1
ITPUB9周年纪念徽章
日期:2010-10-08 09:28:52
17#
发表于 2010-9-28 14:44 | 只看该作者
插,这个好冷啊

使用道具 举报

回复
论坛徽章:
86
2015中国数据库技术大会纪念徽章
日期:2015-04-24 16:04:24马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11优秀写手
日期:2013-12-18 09:29:11日产
日期:2013-10-17 08:44:39马自达
日期:2013-08-26 16:28:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-23 16:55:51马上有房
日期:2014-02-19 11:55:14
18#
发表于 2010-9-29 09:50 | 只看该作者
原帖由 hponiang 于 2010-9-24 14:03 发表
在这里和大家说一下,这种方法不行,因大数据量使用全表扫描的时候sys_context与直接变量绑定的差异很大,因为sys_context其实也相当于一个函数,从一个内存表中取数据
类似于

    SELECT *  from dba_objects WHERE object_name = (SELECT object_name
           from dba_objects WHERE object_name = 'UNDO$');

这句SQL的执行的时间并不是简单的子查询的用时加上外层查询用时,上面耗时0.2,下面的耗时0.015


   
          SELECT *
           from dba_objects WHERE object_name = 'UNDO$';


我也不是很明白为什么会产生的这样的问题,如果有人明白请告诉我 一下


既然已经全表扫描,那么对于一个表,是不大会有什么区别的

SUNDOG315>create table t (id number,text varchar2(4000));

表已创建。

SUNDOG315>insert into t select 1,object_name from dba_objects;

已创建55087行。

SUNDOG315>insert into t select 2,'aaa' from dual;

已创建 1 行。

SUNDOG315>commit;

提交完成。

SUNDOG315>exec dbms_stats.gather_table_stats(user,'T',null,null,method_opt=>'for
all columns',cascade=>true);

PL/SQL 过程已成功完成。

SUNDOG315>select count(*) from t where id=2;

  COUNT(*)
----------
         1

SUNDOG315>select * from table(dbms_xplan.display_cursor());

SQL_ID  8tfp2xac71yd6, child number 0
-------------------------------------
select count(*) from t where id=2

Plan hash value: 2966233522

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |       |       |   102 (100)|          |
|   1 |  SORT AGGREGATE    |      |     1 |     3 |            |          |
|*  2 |   TABLE ACCESS FULL| T    |     1 |     3 |   102   (0)| 00:00:02 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("ID"=2)

已选择19行。

SUNDOG315>create context test using test_p;

上下文已创建。

SUNDOG315>create or replace procedure test_p is
  2  begin
  3    dbms_session.set_context('TEST','ID',2);
  4  end;
  5  /

过程已创建。

SUNDOG315>exec test_p;

PL/SQL 过程已成功完成。

SUNDOG315>select sys_context('TEST','ID') from dual;

SYS_CONTEXT('TEST','ID')
--------------------------------------------------------------------------------

2

SUNDOG315>select count(*) from t where id=sys_context('test','id');

  COUNT(*)
----------
         1

SUNDOG315>select * from table(dbms_xplan.display_cursor());

SQL_ID  69x691fhtckm0, child number 0
-------------------------------------
select count(*) from t where id=sys_context('test','id')

Plan hash value: 2966233522

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |       |       |   103 (100)|          |
|   1 |  SORT AGGREGATE    |      |     1 |     3 |            |          |
|*  2 |   TABLE ACCESS FULL| T    | 27544 | 82632 |   103   (1)| 00:00:02 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("ID"=TO_NUMBER(SYS_CONTEXT('test','id')))


已选择19行。

SUNDOG315>set autot trace stat
SUNDOG315>select count(*) from t where id=2;


统计信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
        300  consistent gets
          0  physical reads
          0  redo size
        423  bytes sent via SQL*Net to client
        415  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SUNDOG315>select count(*) from t where id=sys_context('test','id');


统计信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
        300  consistent gets
          0  physical reads
          0  redo size
        423  bytes sent via SQL*Net to client
        415  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

使用道具 举报

回复
论坛徽章:
86
2015中国数据库技术大会纪念徽章
日期:2015-04-24 16:04:24马上有车
日期:2014-02-19 11:55:14马上有车
日期:2014-02-18 16:41:112014年新春福章
日期:2014-02-18 16:41:11优秀写手
日期:2013-12-18 09:29:11日产
日期:2013-10-17 08:44:39马自达
日期:2013-08-26 16:28:022013年新春福章
日期:2013-02-25 14:51:24ITPUB 11周年纪念徽章
日期:2012-10-23 16:55:51马上有房
日期:2014-02-19 11:55:14
19#
发表于 2010-9-29 09:59 | 只看该作者
但是,如果在ID列有索引,不绑定SQL和普通变量绑定SQL,由于bind peeking的存在,都会选择正确的执行计划。sys_context由于将值进行了封装,无法进行bind peeking,将会导致选择错误的执行计划

SQL*Plus: Release 11.2.0.1.0 Production on 星期三 9月 29 08:43:56 2010

Copyright (c) 1982, 2010, Oracle.  All rights reserved.

SUNDOG315>conn test/test
已连接。
SUNDOG315>create table t (id number,text varchar2(4000));

表已创建。

SUNDOG315>insert into t select 1,object_name from dba_objects;

已创建55085行。

SUNDOG315>insert into t select 2,'aaa' from dual;

已创建 1 行。

SUNDOG315>commit;

提交完成。

SUNDOG315>create index t_idx on t(id);

索引已创建。

SUNDOG315>exec dbms_stats.gather_table_stats(user,'T',null,null,method_opt=>'for
all columns',cascade=>true);

PL/SQL 过程已成功完成。

SUNDOG315>select id,count(*) from t group by id;

        ID   COUNT(*)
---------- ----------
         1      55085
         2          1

SUNDOG315>select count(*) from t where id=2;

  COUNT(*)
----------
         1

SUNDOG315>select * from table(dbms_xplan.display_cursor());

SQL_ID  8tfp2xac71yd6, child number 0
-------------------------------------
select count(*) from t where id=2

Plan hash value: 293504097

---------------------------------------------------------------------------
| Id  | Operation         | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |       |       |       |     1 (100)|          |
|   1 |  SORT AGGREGATE   |       |     1 |     3 |            |          |
|*  2 |   INDEX RANGE SCAN| T_IDX |     1 |     3 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("ID"=2)

已选择19行。

--选择了正确的索引范围扫描

SUNDOG315>var fid number;
SUNDOG315>exec :fid := 2;

PL/SQL 过程已成功完成。


SUNDOG315>select count(*) from t where id=:fid;

  COUNT(*)
----------
         1

SUNDOG315>select * from table(dbms_xplan.display_cursor());

SQL_ID  3u1847dua6k75, child number 0
-------------------------------------
select count(*) from t where id=:fid

Plan hash value: 293504097

---------------------------------------------------------------------------
| Id  | Operation         | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |       |       |       |     1 (100)|          |
|   1 |  SORT AGGREGATE   |       |     1 |     3 |            |          |
|*  2 |   INDEX RANGE SCAN| T_IDX |     1 |     3 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("ID"=:FID)

已选择19行。

--由于bind_peeking的存在,依然选择了正确的索引范围扫描

SUNDOG315>create context test using test_p;

上下文已创建。

SUNDOG315>create or replace procedure test_p is
  2  begin
  3    dbms_session.set_context('test','id',2);
  4  end;
  5  /

过程已创建。

SUNDOG315>exec test_p;

PL/SQL 过程已成功完成。

SUNDOG315>select sys_context('TEST','ID') from dual;

SYS_CONTEXT('TEST','ID')
--------------------------------------------------------------------------------

2

SUNDOG315>select count(*) from t where id=sys_context('test','id');

  COUNT(*)
----------
         1

SUNDOG315>select * from table(dbms_xplan.display_cursor());

SQL_ID  69x691fhtckm0, child number 0
-------------------------------------
select count(*) from t where id=sys_context('test','id')

Plan hash value: 1058879072

-------------------------------------------------------------------------------
| Id  | Operation             | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |       |       |       |    32 (100)|          |
|   1 |  SORT AGGREGATE       |       |     1 |     3 |            |          |
|*  2 |   INDEX FAST FULL SCAN| T_IDX | 27543 | 82629 |    32   (4)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("ID"=TO_NUMBER(SYS_CONTEXT('test','id')))

已选择19行。

--TO_NUMBER(SYS_CONTEXT('test','id'))无法peeking到正确的值,因此,选择了错误的执行计划

SUNDOG315>set autot trace stat
SUNDOG315>select count(*) from t where id=2;


统计信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          2  consistent gets
          0  physical reads
          0  redo size
        423  bytes sent via SQL*Net to client
        415  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SUNDOG315>select count(*) from t where id=:fid;


统计信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          2  consistent gets
          0  physical reads
          0  redo size
        423  bytes sent via SQL*Net to client
        415  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

SUNDOG315>select count(*) from t where id=sys_context('test','id');


统计信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
        116  consistent gets                                 --逻辑读增大
          0  physical reads
          0  redo size
        423  bytes sent via SQL*Net to client
        415  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed


目前,估计用dbms_session的人还是比较少,像这种问题,Oracle其实完全可以处理掉的。估计如果使用的人多,就会进行处理了。呵呵

使用道具 举报

回复
论坛徽章:
1
ITPUB9周年纪念徽章
日期:2010-10-08 09:28:52
20#
发表于 2010-9-29 10:49 | 只看该作者

回复 #19 sundog315 的帖子

执行计划我也关注过程,二者完全是一样的,但我在plsql里执行的耗时很有差异
我发现如果列出列名二者的差异就会少好多


  1. SELECT *  from dba_objects WHERE object_name = (SELECT object_name
  2.            from dba_objects WHERE object_name =  'UNDO$');

  3.    
  4.           SELECT *
  5.            from dba_objects WHERE object_name = 'UNDO$';

复制代码

你就用这二句进行测试就可得知,如果你觉得这个视图太复杂,不便于分析你可以找一个你们使用中类似的表,要求 [object_name = 'UNDO$'](能唯一确定一条值且这列上没有索引)

[ 本帖最后由 hponiang 于 2010-9-29 10:54 编辑 ]

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表