oracle设计shared pool内存的一个主要目的就是语句共享,通过语句共享,节省语句的解析时间,从而得到性能的提升。如果解释shared pool内存,工作量太大,这里只是做一个非常简单的演示。 查看语句共享可以借助两个数据字典:v$sqlarea和v$sql v$sqlarea:保
oracle设计shared pool内存的一个主要目的就是语句共享,通过语句共享,节省语句的解析时间,从而得到性能的提升。如果解释shared pool内存,工作量太大,这里只是做一个非常简单的演示。
查看语句共享可以借助两个数据字典:v$sqlarea和v$sql
v$sqlarea:保留sql语句的父游标信息,可以通过sql_id标识,其中的version_count列表示子游标的数量
v$sql :保留sql语句的子游标信息,可以通过sql_id和child_number标识
v$sql_shared_cursor:语句产生子游标的原因
首先确认参数cursor_sharing,默认值是exact,也就是说只有在不使用绑定变量的情况下,语句要完全一样才可以共享,包括大小写、空格回车等所有都要一样。
sql> conn / as sysdba
connected.
sql> show parameter cursor_sharing
name type value
------------------------------------ ----------- ------------------------------
cursor_sharing string exact
清空shared_pool内存,这个命令可以在实验的时候使用,在生产系统库要谨慎
sql> alter system flush shared_pool;
system altered.
在scott用户下和tj用户下有一模一样的表叫做demo,这是我准备的实验场景,以下操作,浅色表示第一个窗口或者session,深色表示在另外一个窗口或session查询动态性能视图信息验证
在第一个窗口:
sql> conn scott/tiger
connected.
sql> select * from demo;
empno ename sal
---------- ---------- ----------
7369 smith 1200
7499 allen 1600
7521 ward 1250
7566 jones 2975
sql> select empno,ename from demo where empno=7369;
empno ename
---------- ----------
7369 smith
由于上边这条语句是清空share pool后第一次执行,所以oracle要做硬解析,生成游标,确切来讲是一个父游标和一个子游标,分别可以通过v$sqlarea和v$sql查到相关信息
在第二个窗口:
[oracle@asm11g workshop]$ sqlplus / as sysdba
sql*plus: release 11.2.0.3.0 production on sun sep 16 21:20:24 2012
copyright (c) 1982, 2011, oracle. all rights reserved.
connected to:
oracle database 11g enterprise edition release 11.2.0.3.0 - 64bit production
with the partitioning, automatic storage management, olap, data mining
and real application testing options
sql> get qs.sql
1 col sql_text for a50
2 set linesize 120
3 col exec for 999
4 col invalid for 99
5 col loads for 999
6 select sql_text,
7 sql_id,
8 hash_value,
9 executions exec,
10 loads,
11 invalidations invalid
12 from v$sqlarea
13* where sql_text like '&text%'
sql> @qs
enter value for text: select empno
old 9: where sql_text like '&text%'
new 9: where sql_text like 'select empno%'
sql_text sql_id hash_value exec loads invalid
-------------------------------------------------- ------------- ---------- ---- ----- -------
select empno,ename from demo where empno=7369 dhdkpzyv9b1w7 3063252871 1 1 0
sql> select sql_id,child_number,executions,loads from v$sql where sql_id='dhdkpzyv9b1w7';
sql_id child_number executions loads
------------- ------------ ---------- -----
dhdkpzyv9b1w7 0 1 1
通过查询我们可以看到,v$sqlarea数据字典中的是父游标的信息,语句解析(loads)了一次,执行(exec)了一次,当然在v$sql中也可以看到类似的信息。
到第一个窗口:
sql> select empno,ename from demo where empno=7369;
empno ename
---------- ----------
7369 smith
再一次执行上一条语句,由于语句在share pool内存中已经有游标存在,所以语句会共享。
到第二个窗口:
sql> @qs
enter value for text: select empno
old 9: where sql_text like '&text%'
new 9: where sql_text like 'select empno%'
sql_text sql_id hash_value exec loads invalid
-------------------------------------------------- ------------- ---------- ---- ----- -------
select empno,ename from demo where empno=7369 dhdkpzyv9b1w7 3063252871 2 1 0
sql> select sql_id,child_number,executions,loads from v$sql where sql_id='dhdkpzyv9b1w7';
sql_id child_number executions loads
------------- ------------ ---------- -----
dhdkpzyv9b1w7 0 2 1
通过上面的查询我们可以看到,语句解析(loads)了一次,执行(exec)了两次,在子游标也可以看到相同的信息。
到第一个窗口:
sql> select empno,ename from demo where empno=7499;
empno ename
---------- ----------
7499 allen
这个语句和刚刚的语句的区别在于我把条件改成了7499,这样这就是一个全新的语句,oracle要做硬解析,并在内存中申请新的父子游标。
第二个窗口:
sql> @qs
enter value for text: select empno
old 9: where sql_text like '&text%'
new 9: where sql_text like 'select empno%'
sql_text sql_id hash_value exec loads invalid
-------------------------------------------------- ------------- ---------- ---- ----- -------
select empno,ename from demo where empno=7499 0m3wzw5mrdg8z 1735834911 1 1 0
select empno,ename from demo where empno=7369 dhdkpzyv9b1w7 3063252871 2 1 0
到第一个窗口:
切换用户到tj,tj用户下也有相同的表demo,执行select empno,ename from demo where empno=7369;
sql> conn tj/tj
connected.
sql> select empno,ename from demo where empno=7369;
empno ename
---------- ----------
7369 smith
到第二个窗口:
sql> @qs
enter value for text: select empno
old 9: where sql_text like '&text%'
new 9: where sql_text like 'select empno%'
sql_text sql_id hash_value exec loads invalid
-------------------------------------------------- ------------- ---------- ---- ----- -------
select empno,ename from demo where empno=7499 0m3wzw5mrdg8z 1735834911 1 1 0
select empno,ename from demo where empno=7369 dhdkpzyv9b1w7 3063252871 3 2 0
sql> select sql_id,child_number,executions,loads from v$sql where sql_id='dhdkpzyv9b1w7';
sql_id child_number executions loads
------------- ------------ ---------- -----
dhdkpzyv9b1w7 0 2 1
dhdkpzyv9b1w7 1 1 1
虽然tj用户下的语句和scott用户下写的语句一模一样,但是语意显然不一样,两个demo表属于不同的用户,所以我们看到,oracle的父游标解析(loads)加1,执行次数也加1,从父游标的角度来讲,语句是共享的,而在子游标中,有了区别,新生成了一个子游标child_number 为1,解析(loads)了一次,执行了一次。
到第一个窗口:
再次执行语句
sql> select empno,ename from demo where empno=7369;
empno ename
---------- ----------
7369 smith
到第二个窗口:
sql> @qs
enter value for text: select empno
old 9: where sql_text like '&text%'
new 9: where sql_text like 'select empno%'
sql_text sql_id hash_value exec loads invalid
-------------------------------------------------- ------------- ---------- ---- ----- -------
select empno,ename from demo where empno=7499 0m3wzw5mrdg8z 1735834911 1 1 0
select empno,ename from demo where empno=7369 dhdkpzyv9b1w7 3063252871 4 2 0
sql> select sql_id,child_number,executions,loads from v$sql where sql_id='dhdkpzyv9b1w7';
sql_id child_number executions loads
------------- ------------ ---------- -----
dhdkpzyv9b1w7 0 2 1
dhdkpzyv9b1w7 1 2 1
我们看到语句的父游标解析次数没有增加,执行次数加1,而对于子游标来说,child_number 为1的子游标执行次数加1。
产生子游标的原因很多,比如我上边的用户方案(schema)改变的例子,当然还有很多其他原因也可以导致子游标的产生,比如优化器模式的改变,或者绑定变量的窥视等,如果你想确定是由那种原因造成的,需要查看v$sql_shared_cursor
对于刚才的例子,属于验证/事物检查不匹配
sql> select sql_id,child_number,auth_check_mismatch from v$sql_shared_cursor where sql_id='dhdkpzyv9b1w7';
sql_id child_number a
------------- ------------ -
dhdkpzyv9b1w7 0 n
dhdkpzyv9b1w7 1 y