我们的应用程序开发人员发现这样一个异常现象,某
SQL
语句在使用绑定变量时,执行的时间比不使用绑定变量时要慢很多,甚至慢到数十倍。
在应用程序中,执行的
SQL
如果没有绑定变量,那么可能会导致共享池挣用等待事件的出项。而且,这种情况在很多应用系统的程序开发中很常见。对此,
Oracle
数据库系统提供了一种折中解决方法,将初始化参数
cursor_sharing
的值设置为
force
或
similar
。这样,在
Oracle
中运行的
SQL
,其常量如字符、数字等则会自动转换为变量,从而使得类似
SQL
变得一样,减少共享池挣用。
在出现该问题的数据库系统中,它的初始化参数
cursor_sharing
的值是
force
。
从问题现象看,使用绑定变量的
SQL
执行计划和不使用绑定变量的不一样,前者走的执行计划不合理。
这个
SQL
也比较复杂,
where
子句中既有自定义的变量语句,也有很多常量语句。在常量条件中,有个占位符子句,紧随
where
关键字。
这类写法在
JAVA
中拼装
SQL
语句时很常见。在需要新加条件判断语句时,直接加上
”and xx=yy”
,变成
”where 1=1 and xx=yy”
。
这种写法很通用吧?
(miki西游 @mikixiyou 的文档,原文链接: http://mikixiyou.iteye.com/blog/1552021
)
语句
出现问题的
SQL
语句如下:
SELECT *
FROM (SELECT row_.*, ROWNUM rownum_
FROM (select count(*)
from (select t1.id as id,
'sms' as type,
t1.empid as empid,
t1.deptno as deptno,
t1.content as title,
to_char(t1.send_time, 'yyyy-MM-dd hh24:mi:ss') as plantime,
t1.sysuid as sysuid,
t1.custid as custid,
t1.mobile as contact,
t1.mark as mark
from liantong_send_back t1
where 1 = 1
and t1.send_time >=
to_date('2011-11-01 00:00:00',
'yyyy-mm-dd hh24:mi:ss')
and t1.send_time <
(to_date('2011-12-06 00:00:00',
'yyyy-mm-dd hh24:mi:ss') + 1)
and t1.deptno = '3400'
union all
select t1.id as id,
'sms' as type,
t1.empid as empid,
t1.deptno as deptno,
t1.content as title,
to_char(t1.send_time, 'yyyy-MM-dd hh24:mi:ss') as plantime,
t1.sysuid as sysuid,
t1.custid as custid,
t1.mobile as contact,
t1.mark as mark
from liantong_send t1
where 1 = 1
and t1.send_time >=
to_date('2011-11-01 00:00:00',
'yyyy-mm-dd hh24:mi:ss')
and t1.send_time <
(to_date('2011-12-06 00:00:00',
'yyyy-mm-dd hh24:mi:ss') + 1)
and t1.deptno = '3400') T
where rownum < 10001
order by T.plantime desc, T.id) row_
WHERE ROWNUM <= :b)
WHERE rownum_ > :a
这个
SQL
的内部
where
条件中有一个“
1=1
”的条件,这是开发人员在条件不定时,动态添加条件的常用写法。这种写法在很多类型的应用中都出现过。
这个
SQL
很明显去掉
rownum
的条件判断使用的绑定变量,其他条件都是常量赋值。这是因为内部那个结果集的
SQL
是应用程序拼出来的,条件很灵活,不容易实现带变量的写法。因此我们让数据库系统在执行之前自动去修改这些常量为变量,从而实现不同常量的
SQL
能共享游标(
cursor
),减少硬分析。
设置
cursor_sharing=force
,就实现了这种自动转换。但占位符(“
1=1
”)也会被系统自动替换成
:"SYS_B_02" = :"SYS_B_03"
。
但在
cursor_sharing=exact
时,系统的优化器则是做了另一种操作。它将占位符(“
1=1
”)忽略掉,因为也确实不需要去判断,从而节省
CPU
执行时间。很聪明吧!
分析
我先做了一些简单的测试:
测试一、将
SQL
中设置的变量取消,让
SQL
完全由系统生成绑定变量,语句执行正常;
测试二、将
cursor_sharing
修改成默认值(
exact
),
SQL
使用绑定变量,语句执行也是正常;
测试三、将
SQL
中占位符
(“1=1”)
去掉,应用使用绑定变量,
cursor_sharing
设置为
force
,语句执行也正常。
测试结果显示,如果没有占位符,就正常了。
这是怎么回事呢?
看来,必须去他们各自的分析执行计划才能明白了。
--待续
分享到:
相关推荐
Oracle的CURSOR_SHARING参数是数据库性能优化中的一个重要设置,它决定了SQL语句在什么情况下可以共享相同的游标(cursor)。游标在Oracle数据库中扮演着关键角色,它们是执行查询时保存信息的结构,包括关于如何从...
如果不能使用强制绑定变量的oracle 参数 cursor_sharing=force ,也不能用触发器修改某个用户的 cursor_sharing=force 会话参数,那么这个转换程序可以帮到你(不能解决使用JAVA等编程语言,因为java使用?占位符不...
如果函数执行成功,尽管返回值为 `TRUE`,但并不意味着鼠标位置实际上已经改变,因为用户可能在函数执行期间移动了鼠标,或者由于权限问题无法改变鼠标位置。 在LabVIEW环境中,`set_cursor_pos.vi` 可能是一个封装...
5. **CURSOR_SHARING设置**:合理设置CURSOR_SHARING参数可以帮助数据库更好地共享相同的执行计划,进一步提高查询效率。 #### 示例解析 以Oracle数据库为例,下面将通过几个具体示例来进一步解释上述概念: 1. *...
FETCH cursor_name INTO variable1, variable2; ``` - 处理:根据需要对提取的数据进行处理。 - 关闭:使用CLOSE语句关闭游标,释放资源。 ```sql CLOSE cursor_name; ``` 4. 游标属性 Oracle游标有一些关键属性,...
在这个例子中,`%s`是一个占位符,代表查询参数。通过将参数传递给`execute()`方法的第二个参数,可以确保输入被正确转义,不会被解析为SQL命令的一部分。 #### 四、总结 本文详细介绍了如何使用Python防止SQL注入...
在Oracle数据库管理中,动态执行SQL语句是一种强大的功能,允许开发者在运行时构建和执行SQL语句,这对于处理不确定或变化的数据结构尤其有用。本文将深入探讨Oracle中动态执行SQL的四种主要方法,并通过具体示例...
007_insert_seal_approval_cursor.sql
硬编码SQL由于列值的不同导致无法共享执行计划,而CURSOR_SHARING参数可以通过设置,让数据库在一定程度上接受列值变化但结构相同的SQL作为共享SQL,从而提高效率。 总的来说,分析SQL语句的执行计划涉及多个层面,...
在这个例子中,我们定义了一个过程`define_column`,该过程接受一个数字参数`no`,并根据这个参数执行SQL查询(`SELECT * FROM demo WHERE a = :no`)。这里使用了`define_column`方法来指定结果集中第二列的数据...
这个名为"Python填充SQL参数脚本.zip"的压缩包提供了一个解决方案,旨在解决一个常见的问题:手动替换SQL查询中的占位符(通常是问号'?')以适应实际的数据。在服务器日志中,我们经常发现SQL语句被记录下来,但为了...
最后,我们还可以通过设置`cursor_sharing`参数实现服务器端的变量绑定策略。`cursor_sharing=force`强制所有的绑定变量都被视为相同,`cursor_sharing=exact`则根据变量的实际值创建独立的游标,而`cursor_sharing=...
在本DEMO中,"use_cursor_DEMO"可能包含了以下内容: 1. **代码示例**:DEMO可能包含了一段使用预定义光标的代码,展示了如何在程序中打开、遍历和关闭游标。例如,在Python的DB-API中,可以使用`cursor.execute()`...
从 Oracle 8i 开始,新引入了 CURSOR_SHARING 参数,该参数的主要目的就是为了解决在编程过程中已大量使用的硬编码 SQL 问题。 Oracle 执行计划是 Oracle 数据库性能调整的关键部分,了解这些背景知识和重要概念...
2. **debug**: 09-DEBUG.PC可能包含了调试PL/SQL代码的技巧和示例,这对于解决程序中的错误和性能问题至关重要。 3. **RSINS**: "RSINS"可能是"Row Source Insertion"的缩写,09-RSINS.PC可能涉及到在PL/SQL中插入...
### Oracle 执行动态 SQL 的几种方法 在数据库管理和应用程序开发中,经常需要处理不固定、不可预知的数据查询和更新需求。此时,静态 SQL(即硬编码的 SQL 语句)无法满足这些灵活多变的需求,这就需要使用动态 ...
Python还支持使用参数化查询来防止SQL注入攻击,如下所示: ```python id_to_find = 123 sql_query = "SELECT * FROM your_table_name WHERE id = ?" cursor.execute(sql_query, (id_to_find,)) row = cursor....
DBMS_SQL.PARSE(cursor_id, 'SELECT * FROM table', DBMS_SQL.NATIVE); DBMS_SQL.DEFINE_COLUMN(cursor_id, 1, col_name); DBMS_SQL.EXECUTE(cursor_id); LOOP EXIT WHEN DBMS_SQL.FETCH_ROWS(cursor_id) = 0; ...
存储过程是一组PL/SQL语句,可以接受参数,执行一系列操作并返回结果。函数与存储过程类似,但必须返回一个值。创建存储过程和函数的语法涉及PROCEDURE和FUNCTION关键字,以及IN、OUT、IN OUT参数类型。 7. 触发器...
通过设置CURSOR_SHARING参数,可以强制Oracle将某些具有相同结构但列值不同的SQL语句视为相同,从而提高性能。 总的来说,理解Oracle的执行计划和共享SQL语句的概念对于优化数据库性能至关重要。通过合理配置数据库...