根据Oracle 学习之性能优化(二)游标中的描述,我们知道如下两条语句是不共享的。
select * from emp where empno=7698; select * from emp where empno=7566;
这样就造成每次执行用户的查询都要进行硬解析,但是我们知道,其他这两个语句的执行计划应该是相同。那么有什么方法能避免不必要的硬解析吗?这里我们提供2种方法。
一、绑定变量
SQL> variable empno number; SQL> exec :empno := 7839; PL/SQL procedure successfully completed. SQL> select ename from emp where empno = :empno; ENAME ------------------------------ KING SQL> exec :empno := 7782; PL/SQL procedure successfully completed. SQL> select ename from emp where empno = :empno; ENAME ------------------------------ CLARK SQL>
我们查看一下游标
SQL> COL SQL_TEXT FOR A30 SQL> COL SQL_ID FOR A20 SQL> SET LINESIZE 200 SQL> SELECT sql_id,sql_text,executions,loads,version_count FROM v$sqlarea WHERE sql_text LIKE ‘%:empno‘; SQL_ID SQL_TEXT EXECUTIONS LOADS VERSION_COUNT -------------------- ------------------------------ ---------- ---------- ------------- f6r0kqk0hsa7s select ename from emp where em 2 1 1 pno = :empno SQL> SELECT sql_id,sql_text,loads,child_number,parse_calls FROM v$sql WHERE sql_text LIKE ‘%:empno‘; SQL_ID SQL_TEXT LOADS CHILD_NUMBER PARSE_CALLS -------------------- ------------------------------ ---------- ------------ ----------- f6r0kqk0hsa7s select ename from emp where em 1 0 2 pno = :empno SQL>
可见,父子游标都被共享啦。
在OLTP环境中,一定要使用绑定变量以避免系统有太多的硬解析。
我们验证一下,不使用绑定变量和使用了绑定变量后,性能到底有没有提升。
1. 建立一张表
SQL> create table t(id int,text varchar2(100)); Table created.
2. 不使用绑定变量向表中插入10000行记录
SQL> set timing on SQL> declare begin for i in 1 .. 10000 loop execute immediate ‘insert into t values(‘||i||‘,‘‘test bind variable‘‘)‘; end loop; commit; end; / PL/SQL procedure successfully completed. Elapsed: 00:00:06.43
系统产生了非常多的游标
SQL> set pause on SQL> SELECT sql_text, sql_id, EXECUTIONS, LOADS, VERSION_COUNT FROM v$sqlarea WHERE sql_text LIKE ‘insert into t%‘; SQL_TEXT SQL_ID EXECUTIONS LOADS VERSION_COUNT ------------------------------ -------------------- ---------- ---------- ------------- insert into t values(9156,‘tes ah7vdgtnj80b1 1 1 1 t bind variable‘) insert into t values(8826,‘tes 7yuz09vq9h0c4 1 1 1 t bind variable‘) insert into t values(9905,‘tes 97c7m0gxj80cv 1 1 1 t bind variable‘) insert into t values(9396,‘tes 9bvtw8y7080g5 1 1 1 t bind variable‘) SQL_TEXT SQL_ID EXECUTIONS LOADS VERSION_COUNT ------------------------------ -------------------- ---------- ---------- ------------- insert into t values(9034,‘tes ck51y8bu1c0jr 1 1 1 t bind variable‘) insert into t values(9153,‘tes 7cxb26zpcn0q9 1 1 1 t bind variable‘) insert into t values(9783,‘tes 7236x7yva40sq 1 1 1 t bind variable‘) insert into t values(9491,‘tes cn2n05f70810f 1 1 1
3. 使用绑定变量
SQL> set timing on SQL> declare begin for i in 1 .. 10000 loop execute immediate ‘insert into t values(:x,‘‘test bind variable‘‘)‘ using i; end loop; commit; end; / PL/SQL procedure successfully completed. Elapsed: 00:00:00.43
使用绑定变量,执行速度快了很多倍。
SQL> SELECT sql_text, sql_id, EXECUTIONS, LOADS, VERSION_COUNT FROM v$sqlarea WHERE sql_text LIKE ‘insert into t%:x%‘; SQL_TEXT SQL_ID EXECUTIONS LOADS VERSION_COUNT ------------------------------ -------------------- ---------- ---------- ------------- insert into t values(:x,‘test 0nhbks92x50kk 10000 1 1 bind variable‘)
执行计划只有一个,被执行了10000次。
二、修改初始化参数
系统提供了一个初始化参数
SQL> show parameter cursor_sharing NAME TYPE VALUE ------------------------ ------------------- ------------------ cursor_sharing string EXACT
CURSOR_SHARING determines what kind of SQL statements can share the same
cursors.
Values:
- FORCE
Allows the creation of a new cursor if sharing an existing cursor, or if the cursor
plan is not optimal. - SIMILAR
Causes statements that may differ in some literals, but are otherwise identical, to
share a cursor, unless the literals affect either the meaning of the statement or the
degree to which the plan is optimized. - EXACT
Only allows statements with identical text to share the same cursor
1. 清空shared_pool
SQL> set pagesize 10000 SQL> set linesize 200 SQL> col SQL_TEXT for a50 SQL> col SQL_ID for 520 SQL> col SQL_ID for a20 SQL> alter system flush shared_pool; System altered. SQL> SELECT sql_text, sql_id, EXECUTIONS, LOADS, VERSION_COUNT FROM v$sqlarea WHERE sql_text LIKE ‘insert into t%‘; 2 3 4 5 6 7 no rows selected SQL>
2. 将cursor_sharing改为FORCE,执行查询
SQL> alter session set cursor_sharing=force; Session altered. Elapsed: 00:00:00.02 SQL> declare begin for i in 1 .. 10000 loop execute immediate ‘insert into t values(‘||i||‘,‘‘test bind variable‘‘)‘; end loop; commit; end; / 2 3 4 5 6 7 8 PL/SQL procedure successfully completed. Elapsed: 00:00:01.15
3. 查看游标情况
SQL> SELECT sql_text, sql_id, EXECUTIONS, LOADS, VERSION_COUNT FROM v$sqlarea WHERE sql_text LIKE ‘insert into t%‘; no rows selected SQL> / SQL_TEXT SQL_ID EXECUTIONS LOADS VERSION_COUNT -------------------------------------------------- -------------------- ---------- ---------- ------------- insert into t values(9966,‘test bind variable‘) 07xgdm0uwn5gb 1 3 1 insert into t values(10000,‘test bind variable‘) 76rf2hx2w45m1 1 3 1 insert into t values(9969,‘test bind variable‘) bfayz4q1j4b37 1 3 1 insert into t values(9984,‘test bind variable‘) 48t1dy0tahgxh 1 3 1 insert into t values(9998,‘test bind variable‘) 04bhmfjq8hhtu 1 3 1 insert into t values(9967,‘test bind variable‘) 0njsupf834kn0 1 3 1 insert into t values(9999,‘test bind variable‘) 6uhdudx8k4rv3 1 3 1 insert into t values(9975,‘test bind variable‘) 0tqj0jcamsspu 1 3 1 insert into t values(9957,‘test bind variable‘) a6as35h2wwu00 1 3 1 insert into t values(9970,‘test bind variable‘) 58m581pqq8v4j 1 3 1 insert into t values(9982,‘test bind variable‘) 3gh1q9f2wnxr8 1 3 1 insert into t values(9977,‘test bind variable‘) 1t0t0jz9y0zg9 1 3 1 insert into t values(9988,‘test bind variable‘) 111vappsrszy7 1 3 1 insert into t values(9994,‘test bind variable‘) 8kvjy7tns10vq 1 3 1 insert into t values(9963,‘test bind variable‘) c1w951tadx4tb 1 3 1 insert into t values(9993,‘test bind variable‘) 10h1mbxvtt9tm 1 3 1 insert into t values(9981,‘test bind variable‘) gv77ng7kndhty 1 3 1 insert into t values(9978,‘test bind variable‘) 0v7773365tj70 1 3 1 insert into t values(9974,‘test bind variable‘) astu71gzn1uw5 1 3 1 insert into t values(9960,‘test bind variable‘) 09d0bxcsndxzm 1 3 1 insert into t values(9959,‘test bind variable‘) 7ht6qzyy0jz5w 1 3 1 insert into t values(9965,‘test bind variable‘) dgz4fbhzgpzh4 1 3 1 insert into t values(9989,‘test bind variable‘) 3srf852y19zx6 1 3 1 insert into t values(9995,‘test bind variable‘) 1r6tp423v613x 1 3 1 insert into t values(9976,‘test bind variable‘) 9vxdayk3yq1nn 1 3 1 insert into t values(9958,‘test bind variable‘) 9ptg2jd30k6d8 1 3 1 insert into t values(9968,‘test bind variable‘) akt2u5gn1y9kp 1 3 1 insert into t values(9992,‘test bind variable‘) ch4rx2b3ja9x8 1 3 1 insert into t values(9962,‘test bind variable‘) a2p68fsk6abwz 1 3 1 insert into t values(9997,‘test bind variable‘) f0474tah8ubzq 1 3 1 insert into t values(9972,‘test bind variable‘) gzqpvbrsn6ggk 1 3 1 insert into t values(9983,‘test bind variable‘) ah9r6ghzsugmp 1 3 1 insert into t values(9979,‘test bind variable‘) 2cvqu9h4wagva 1 3 1 insert into t values(9996,‘test bind variable‘) 3h90mc46sqmzr 1 3 1 insert into t values(9961,‘test bind variable‘) 7t8njvfx8fn4y 1 3 1 insert into t values(9987,‘test bind variable‘) 1qxhj0g7cuw8u 1 3 1 insert into t values(9991,‘test bind variable‘) 5n2jahrk5z258 1 3 1 insert into t values(:"SYS_B_0",:"SYS_B_1") 950r47takm3c4 9953 1 1 insert into t values(9971,‘test bind variable‘) fyb5pvjuqz4d0 1 3 1 insert into t values(9955,‘test bind variable‘) 1adu3pctt76bp 1 3 1 insert into t values(9990,‘test bind variable‘) 62pp4zqc9r767 1 3 1 insert into t values(9973,‘test bind variable‘) adb60k3nxr9mk 1 3 1 insert into t values(9985,‘test bind variable‘) gz4hry47rzhvt 1 3 1 insert into t values(9986,‘test bind variable‘) b54fdtcu47v0d 1 3 1 insert into t values(9980,‘test bind variable‘) fvwh43nh6zvhk 1 3 1 insert into t values(9956,‘test bind variable‘) 1vcjq6rm9gx72 1 3 1 insert into t values(9964,‘test bind variable‘) a06un7tf1rxgu 1 3 1 insert into t values(9954,‘test bind variable‘) 0nb4synx6bxqv 1 3 1 48 rows selected. SQL>
4. 再次清空shared_pool
SQL> alter system flush shared_pool; System altered.
5. 将cursor_sharing改为SIMILAR,执行查询
SQL> alter session set cursor_sharing=similar; Session altered. Elapsed: 00:00:00.03 SQL> declare begin for i in 1 .. 10000 loop execute immediate ‘insert into t values(‘||i||‘,‘‘test bind variable‘‘)‘; end loop; commit; end; / 2 3 4 5 6 7 8 PL/SQL procedure successfully completed. Elapsed: 00:00:01.14
5. 查看共享游标
SQL> SELECT sql_text, sql_id, EXECUTIONS, LOADS, VERSION_COUNT FROM v$sqlarea WHERE sql_text LIKE ‘insert into t%‘; 2 3 4 5 6 7 SQL_TEXT SQL_ID EXECUTIONS LOADS VERSION_COUNT -------------------------------------------------- -------------------- ---------- ---------- ------------- insert into t values(9966,‘test bind variable‘) 07xgdm0uwn5gb 1 4 1 insert into t values(10000,‘test bind variable‘) 76rf2hx2w45m1 1 4 1 insert into t values(9969,‘test bind variable‘) bfayz4q1j4b37 1 4 1 insert into t values(9984,‘test bind variable‘) 48t1dy0tahgxh 1 4 1 insert into t values(9998,‘test bind variable‘) 04bhmfjq8hhtu 1 4 1 insert into t values(9967,‘test bind variable‘) 0njsupf834kn0 1 4 1 insert into t values(9999,‘test bind variable‘) 6uhdudx8k4rv3 1 4 1 insert into t values(9975,‘test bind variable‘) 0tqj0jcamsspu 1 4 1 insert into t values(9957,‘test bind variable‘) a6as35h2wwu00 1 4 1 insert into t values(9970,‘test bind variable‘) 58m581pqq8v4j 1 4 1 insert into t values(9982,‘test bind variable‘) 3gh1q9f2wnxr8 1 4 1 insert into t values(9977,‘test bind variable‘) 1t0t0jz9y0zg9 1 4 1 insert into t values(9988,‘test bind variable‘) 111vappsrszy7 1 4 1 insert into t values(9994,‘test bind variable‘) 8kvjy7tns10vq 1 4 1 insert into t values(9963,‘test bind variable‘) c1w951tadx4tb 1 4 1 insert into t values(9993,‘test bind variable‘) 10h1mbxvtt9tm 1 4 1 insert into t values(9981,‘test bind variable‘) gv77ng7kndhty 1 4 1 insert into t values(9978,‘test bind variable‘) 0v7773365tj70 1 4 1 insert into t values(9974,‘test bind variable‘) astu71gzn1uw5 1 4 1 insert into t values(9960,‘test bind variable‘) 09d0bxcsndxzm 1 4 1 insert into t values(9959,‘test bind variable‘) 7ht6qzyy0jz5w 1 4 1 insert into t values(9965,‘test bind variable‘) dgz4fbhzgpzh4 1 4 1 insert into t values(9989,‘test bind variable‘) 3srf852y19zx6 1 4 1 insert into t values(9995,‘test bind variable‘) 1r6tp423v613x 1 4 1 insert into t values(9976,‘test bind variable‘) 9vxdayk3yq1nn 1 4 1 insert into t values(9958,‘test bind variable‘) 9ptg2jd30k6d8 1 4 1 insert into t values(9968,‘test bind variable‘) akt2u5gn1y9kp 1 4 1 insert into t values(9992,‘test bind variable‘) ch4rx2b3ja9x8 1 4 1 insert into t values(9962,‘test bind variable‘) a2p68fsk6abwz 1 4 1 insert into t values(9997,‘test bind variable‘) f0474tah8ubzq 1 4 1 insert into t values(9972,‘test bind variable‘) gzqpvbrsn6ggk 1 4 1 insert into t values(9983,‘test bind variable‘) ah9r6ghzsugmp 1 4 1 insert into t values(9979,‘test bind variable‘) 2cvqu9h4wagva 1 4 1 insert into t values(9996,‘test bind variable‘) 3h90mc46sqmzr 1 4 1 insert into t values(9961,‘test bind variable‘) 7t8njvfx8fn4y 1 4 1 insert into t values(9987,‘test bind variable‘) 1qxhj0g7cuw8u 1 4 1 insert into t values(9991,‘test bind variable‘) 5n2jahrk5z258 1 4 1 insert into t values(:"SYS_B_0",:"SYS_B_1") 950r47takm3c4 9953 1 1 insert into t values(9971,‘test bind variable‘) fyb5pvjuqz4d0 1 4 1 insert into t values(9955,‘test bind variable‘) 1adu3pctt76bp 1 4 1 insert into t values(9990,‘test bind variable‘) 62pp4zqc9r767 1 4 1 insert into t values(9973,‘test bind variable‘) adb60k3nxr9mk 1 4 1 insert into t values(9985,‘test bind variable‘) gz4hry47rzhvt 1 4 1 insert into t values(9986,‘test bind variable‘) b54fdtcu47v0d 1 4 1 insert into t values(9980,‘test bind variable‘) fvwh43nh6zvhk 1 4 1 insert into t values(9956,‘test bind variable‘) 1vcjq6rm9gx72 1 4 1 insert into t values(9964,‘test bind variable‘) a06un7tf1rxgu 1 4 1 insert into t values(9954,‘test bind variable‘) 0nb4synx6bxqv 1 4 1 48 rows selected.
和cursor_sharing=FORCE时,情况一样。
这两种方法都不推荐使用,有bug 。建议规范前台业务查询,尽量使用绑定变量。
时间: 2024-12-23 15:23:14