什么是Oracle的高版本游标(High Version Count)?如何排查?
简介
一个父游标下对应的子游标个数被称为Version Count,每个子游标对应一个执行计划。对于一个特定的游标有多少个版本(Version Count)就属于高版本游标是没有明确定义的。对于不同的系统有不同的数量界定。High Version Count不仅产生的原因是多种多样的,而且会导致各种令人头痛的问题,轻则导致数据库的性能急剧下降,CPU利用率剧增,重则导致数据库挂起,触发ORA-04031或者其它BUG导致宕机。
在AWR报告中,默认Version Count大于20就会被报告出来,如下图所示:
image-20240414175413082
SQL执行计划的生成,是受到很多因素影响的。相同父游标只是表示输入SQL的字面值相同。子游标对应的因素,如优化器类型、优化器的模式(OPTIMIZER_MODE)、对应对象权限等的差异,都会影响到子游标的共享。
AWR报告中SQL统计部分的执行次数和每次执行时间为空的说明 (Doc ID 1522547.1)
从Oracle 10.2开始,若Version Count大于200,则Executions和 "Elap per Exec(s)"列不再自动收集,因为会引起性能问题,可以参考Why "Executions" and "Elap per Exec(s)" are 'Blank' in AWR for Some SQL Statements (Doc ID 1522547.1)。
参考:https://xmmup.com/awrbaogaozhongsqltongjibufendezhixingcishuhemeicizhixingshijianweikongdeshuoming-doc-id-15225471.html
游标不共享的原因整理
在Oracle 11g中,V$SQL_SHARED_CURSOR
可以用来诊断子游标不共享问题的原因。该视图通过SQL_ID和CHILD_NUMBER就可以定义某个特定子游标的信息。该视图中大部分列都是以VARCHAR2(1)的Y/N取值,每列的含义都是一个不能共享的理由。需要注意的是,这个理由Y表示的是不能与第一个子游标(CHILD_NUMBER=0)共享的理由。
下面是原因列表以及实际例子(标记的是非常常见原因) :
UNBOUND_CURSOR 现有的子游标没有构建完全(换言之, 该子游标没有被优化).
SQL_TYPE_MISMATCH SQL类型与现有的子游标不匹配。例如,在两个版本不同的客户端上运行同一个应用程序,在服务器中产生不同的子游标。
OPTIMIZER_MISMATCH 优化器环境与现有的子游标不匹配 (修改优化器模式之后,现有的子游标不能被重新使用)。在高版本中,修改参数statistics_level也会因为OPTIMIZER_MISMATCH导致不能共享。
例如:
1select count(*) from emp; ->> 1 父, 1 子游标<br>2alter session set optimizer_mode=ALL_ROWS<br>3select count(*) from emp; ->> 1 父, 2 子游标<br>
注: 该行为适用于跟踪事件的设置。例如,如果使用 10046 打开跟踪,将新添加一个由于OPTIMIZER_MISMATCH引起的子游标。
OUTLINE_MISMATCHOUTLINES 与现有的子游标不一致。例如:如果用户之前为这个SQL创建了存储OUTLINES,并且这些OUTLINES被存储在不同的分类里(称为"OUTLINES1" 和 "OUTLINES2")。如果执行下面的命令:
1alter session set use_stored_outlines = OUTLINES1;<br>2select count(*) from emp;<br>3<br>4alter session set use_stored_oulines= OUTLINES2;<br>5select count(*) from emp;<br>
第二次执行"select from emp" 将创建另一个子游标,因为使用的OUTLINES与第一次运行的OUTLINES不同。这个子游标将被标记为 OUTLINE_MISMATCH。
STATS_ROW_MISMATCH现有的统计数据与现有的子游标不匹配。检查是否在所有会话上都设置了10046/sql_trace,因为这可能导致这种情况。
LITERAL_MISMATCH非数据字面值与现有的子游标不匹配。
SEC_DEPTH_MISMATCH安全级别与现有的子游标不匹配。
EXPLAIN_PLAN_CURSOR子游标是一个 explain plan 游标,不应该被共享。 explain plan 句将默认生成一个新的子游标--这种情况将不匹配。
BUFFERED_DML_MISMATCH缓冲的DML与现有的子游标不匹配。
PDML_ENV_MISMATCH PDML环境与现有的子游标不匹配。参数 parallel_dml_mode 和/或 parallel_max_degree 可能已经改变。
INST_DRTLD_MISMATCH 直接加载插入与现有的子游标不匹配。
SLAVE_QC_MISMATCH 现有的子游标是一个工作游标,而新的游标是由协调者发出的(或者,现有的子游标是由协调者发出的,而新的是一个工作游标)。
TYPECHECK_MISMATCH 现有的子游标没有完全优化。
AUTH_CHECK_MISMATCH 对于现有的子游标,认证/翻译检查失败。用户没有权限访问以前任何版本游标中的对象。一个典型的例子是,对于一个表,每个用户都有一个属于自己的副本。
BIND_MISMATCH: 绑定元数据与现有的子游标不匹配,常见原因:
① 变量长度问题,包括声明变量长度(变量的定义长度)跨度很大和传入的具体值的长度跨度很大(同一个变量值,传入的长度出现在(0,32]、[33,128]、[129,2000]、(2000++)区间,出现绑定变量分级
② 变量类型问题(如传入TIMESTAMP,但列类型为DATE)等
③ SQL绑定变量输入null值触发BUG 8198150
例如,在下面的语句中,绑定变量'a'的定义在两条语句中发生了变化,但在这里是因为BIND_LENGTH_UPGRADEABLE的原因,早期版本归于BIND_MISMATCH:
1 variable a varchar2(10);<br> 2 select count(*) from scott.emp where ename = :a ; ->> 1 PARENT, 1 CHILD<br> 3<br> 4 variable a varchar2(2000);<br> 5 select count(*) from scott.emp where ename = :a ; ->> 1 PARENT, 2 CHILDREN <br> 6<br> 7<br> 8 col sql_text format a60<br> 9 select a.sql_text, a.sql_id,a.executions,CHILD_NUMBER from v$sql a where a.sql_text like '%select count(*) from scott.emp where ename%' and a.sql_text not like '%v$sql%';<br>10 select a.sql_id,a.bind_mismatch,a.BIND_LENGTH_UPGRADEABLE from v$sql_shared_cursor a where a.sql_id ='5tvfxfkm0b81p';<br>11<br>12 col name format a10<br>13 col DATATYPE_STRING format a20<br>14 select sql_id,child_number,name,datatype_string,max_length from v$sql_bind_capture a where a.sql_id='5tvfxfkm0b81p' order by CHILD_NUMBER;<br>15<br>16 -- alter system flush shared_pool;<br>17<br>18<br>19<br>20 SYS@ORCLCDB> select banner_full from v$version;<br>21<br>22 BANNER_FULL<br>23 -----------------------------------------------------------------------------------------<br>24 Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production<br>25 Version 19.3.0.0.0<br>26 SYS@ORCLCDB> variable a varchar2(10);<br>27 SYS@ORCLCDB> select count(*) from scott.emp where ename = :a ;<br>28<br>29 COUNT(*)<br>30 ----------<br>31 0<br>32<br>33 SYS@ORCLCDB> variable a varchar2(2000);<br>34 SYS@ORCLCDB> select count(*) from scott.emp where ename = :a ; <br>35<br>36 COUNT(*)<br>37 ----------<br>38 0<br>39<br>40 SYS@ORCLCDB> select a.sql_id,a.bind_mismatch,a.BIND_LENGTH_UPGRADEABLE from v$sql_shared_cursor a where a.sql_id ='5tvfxfkm0b81p';<br>41<br>42 SQL_ID BI BI<br>43 -------------------------- -- --<br>44 5tvfxfkm0b81p N N<br>45 5tvfxfkm0b81p N Y<br>46<br>47<br>48 SYS@ORCLCDB> col sql_text format a60<br>49 SYS@ORCLCDB> select a.sql_text, a.sql_id,a.executions,CHILD_NUMBER from v$sql a where a.sql_text like '%select count(*) from scott.emp where ename%' and a.sql_text not like '%v$sql%';<br>50<br>51 SQL_TEXT SQL_ID EXECUTIONS CHILD_NUMBER<br>52 ------------------------------------------------------------ -------------------------- ---------- ------------<br>53 select count(*) from scott.emp where ename = :a 5tvfxfkm0b81p 1 0<br>54 select count(*) from scott.emp where ename = :a 5tvfxfkm0b81p 1 1<br>55<br>56<br>57 SYS@ORCLCDB> select sql_id,child_number,name,datatype_string,max_length from v$sql_bind_capture a where a.sql_id='5tvfxfkm0b81p' order by CHILD_NUMBER;<br>58<br>59 SQL_ID CHILD_NUMBER NAME DATATYPE_STRING MAX_LENGTH<br>60 -------------------------- ------------ ---------- -------------------- ----------<br>61 5tvfxfkm0b81p 0 :A VARCHAR2(32) 32<br>62 5tvfxfkm0b81p 1 :A VARCHAR2(8192) 8192<br>
1USER1:<br>2select count(*) from table@remote_db <br>3<br>4USER2:<br>5select count(*) from table@remote_db <br>