我们都知道绑定变量可以减少软解析。
可是对于表的数据倾斜列,使用绑定变量有个坏处,那就是优化器可能会产生性能低下的执行计划。
对于一个使用绑定变量的SQL语句,第一次执行的时候,优化器会使用一个叫做BIND PEEKING的技术,对绑定变量的值进行绑定窥探(BAND PEEKING),来生成执行计划,以后再执行同样的语句,会依赖于第一次执行时的执行计划。
对于数据倾斜列,由于BIND PEEKING的特点,可能会产生性能非常低下的执行计划。
下面看看测试情况:
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production
1)不使用绑定变量的情况。
测试表tab,其中列B为倾斜列。
SQL> desc tab;
名称 是否为空? 类型
a number
b number
SQL> select b,count(1) from tab group by b;
B COUNT(1)
---------- ----------
1 1
2 1
3 1
4 1
5 9991
9996 1
9997 1
9998 1
9999 1
10000 1
可以看出列值等于5的占了绝大数。
create index ind_tab_b on tab(b);
分析表:
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'SCOTT',
TABNAME => 'TAB',
CASCADE => TRUE);
END;
然后执行查询:
SQL> select * from tab where b=1;
A B
---------- ----------
1 1
已用时间: 00: 00: 00.00
SQL> select * from table(dbms_xplan.display_cursor);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------
--------
SQL_ID 8vjf9k7jrfbh5, child number 0
-------------------------------------
select * from tab where b=:"SYS_B_0"
Plan hash value: 1668701379
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | TABLE ACCESS BY INDEX ROWID| TAB | 1 | 6 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | SS | 1 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("B"=:SYS_B_0)
已选择19行。
已用时间: 00: 00: 00.17
SQL> select * from tab where b=5;
已用时间: 00: 00: 00.00
执行计划
----------------------------------------------------------
Plan hash value: 1995730731
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9991 | 59946 | 6 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TAB | 9991 | 59946 | 6 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("B"=5)
可以看到产生了我们预想的正确的执行计划。
[ 本帖最后由 wei-xh 于 2010-5-8 19:49 编辑 ]
可是对于表的数据倾斜列,使用绑定变量有个坏处,那就是优化器可能会产生性能低下的执行计划。
对于一个使用绑定变量的SQL语句,第一次执行的时候,优化器会使用一个叫做BIND PEEKING的技术,对绑定变量的值进行绑定窥探(BAND PEEKING),来生成执行计划,以后再执行同样的语句,会依赖于第一次执行时的执行计划。
对于数据倾斜列,由于BIND PEEKING的特点,可能会产生性能非常低下的执行计划。
下面看看测试情况:
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production
1)不使用绑定变量的情况。
测试表tab,其中列B为倾斜列。
SQL> desc tab;
名称 是否为空? 类型
a number
b number
SQL> select b,count(1) from tab group by b;
B COUNT(1)
---------- ----------
1 1
2 1
3 1
4 1
5 9991
9996 1
9997 1
9998 1
9999 1
10000 1
可以看出列值等于5的占了绝大数。
create index ind_tab_b on tab(b);
分析表:
BEGIN
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME => 'SCOTT',
TABNAME => 'TAB',
CASCADE => TRUE);
END;
然后执行查询:
SQL> select * from tab where b=1;
A B
---------- ----------
1 1
已用时间: 00: 00: 00.00
SQL> select * from table(dbms_xplan.display_cursor);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------
--------
SQL_ID 8vjf9k7jrfbh5, child number 0
-------------------------------------
select * from tab where b=:"SYS_B_0"
Plan hash value: 1668701379
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | TABLE ACCESS BY INDEX ROWID| TAB | 1 | 6 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | SS | 1 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("B"=:SYS_B_0)
已选择19行。
已用时间: 00: 00: 00.17
SQL> select * from tab where b=5;
已用时间: 00: 00: 00.00
执行计划
----------------------------------------------------------
Plan hash value: 1995730731
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9991 | 59946 | 6 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| TAB | 9991 | 59946 | 6 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("B"=5)
可以看到产生了我们预想的正确的执行计划。
[ 本帖最后由 wei-xh 于 2010-5-8 19:49 编辑 ]
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/22034023/viewspace-662254/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/22034023/viewspace-662254/
本文通过实例演示了在Oracle数据库中使用绑定变量时可能产生的性能问题。特别是在数据倾斜的情况下,优化器生成的执行计划可能不是最优选。文章对比了使用与不使用绑定变量时的不同执行计划。

被折叠的 条评论
为什么被折叠?



