Oracle对索引做monitoring和nomonitoring会导致游标失效的实验

2024年 6月 14日 82.6k 0

简介

在Oracle中,导致游标失效的原因有很多,例如,当对对象(如表或视图)进行DDL 或收集统计信息时,依赖于它们的游标将失效。这里的DDL包括truncate表、索引重建、monitoring和nomonitoring索引,grant、alter操作等等, 这将导致游标在下一次执行时被硬解析,并会影响 CPU 和发生锁竞争。如果存在并发的DDL操作和DML,而DDL一直未完成,此时DDL会持有该对象的library cache object handle的X Lock,DML会请求该对象的Library cache object handle的S lock模式,此时DML就会被hang住。

1此时,AWR 或者 statspack 报告:
2
3    - Library Cache statistics 部分显示 reloads 数很高并且  (每小时几千次) invalidations ( Invali- dations)也很高。
4    - "% SQL with executions>1" 超过 60%, 表明SQL语句共享率较高。
5    - 确认 Dictionary Statistics 部分中的“Modification Requests”的值是否为0,这意味着一些对象上有DDL在执行。

Oracle对索引做monitoring和nomonitoring会导致游标失效的实验-1

Library cache object 失效过多的解决方法:

  1. 不要在数据库繁忙的时间段执行DDL或DCL:DDL 或DCL语句使库缓存对象(Library cache object)失效,并会涉及到许多依赖对象,比如游标。 对象失效后需要同时进行多次硬解析,对库缓存、共享池、字典缓存、CPU使用产生很大影响。 这里的DDL包括truncate表、索引重建、monitoring和nomonitoring索引,grant操作等等都会引起游标失效。

  2. 不要在数据库繁忙的时间段收集统计信息:收集统计信息(ANALYZE或者DBMS_STATS)会使库缓存对象失效,并会涉及到许多依赖对象,比如游标。 对象失效后需要同时进行多次硬解析,对库缓存、共享池、字典缓存、CPU使用产生很大影响。

  3. 不要在数据库繁忙的时间段执行 TRUNCATE 操作: 参考:Truncate - Causes Invalidations in the LIBRARY CACHE (Doc ID 123214.1)

若大量的游标失效,必然会发生大量的硬解析,并发的SQL硬解析则会出现library cache lock竞争(对象在table的library cache object handle的library cache lock)  ,从而会引起严重的library cache lock等待。

我们今天主要是通过实验来验证“monitoring和nomonitoring索引会造成游标失效”的这一现象。

实验1

版本:Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production

1 DROP TABLE T_BG_20240613_LHR_02;
2 CREATE TABLE T_BG_20240613_LHR_02(N NUMBER,V VARCHAR2(4000), v2 date); 
3
4 CREATE INDEX idx_T_BG_20240613_LHR_02_N on  T_BG_20240613_LHR_02(N);
5
6 SELECT COUNT(*) FROM T_BG_20240613_LHR_02;
7 SELECT * FROM T_BG_20240613_LHR_02; 
8 truncate table  T_BG_20240613_LHR_02;
9
10 -- 插入将近10万行数据,生成多个游标 
11 begin     
12
13         FOR i IN 1..3000 LOOP
14                    -- alter system flush shared_pool;
15                     DECLARE
16                        N1 NUMBER := TRUNC(DBMS_RANDOM.VALUE(1, i)) ; 
17                        -- N1 VARCHAR2(11) := TRUNC(DBMS_RANDOM.VALUE(1, i)) ;
18
19                       V1 VARCHAR2(32767) := lpad('1', i, '1');          
20                       --V1 NUMBER := lpad('1', i, '1');          
21                      --V1 NVARCHAR2(4000) := lpad('1', i, '1');    
22                      --V1 char(4000) := lpad('1', i, '1');
23
24
25                         V2 DATE := sysdate+ DBMS_RANDOM.VALUE(-i, i) ; 
26                        -- V2 TIMESTAMP := sysdate+ DBMS_RANDOM.VALUE(-i, i) ; 
27
28
29                     begin  
30
31                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING N1, V1 ,V2; 
32                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_CHAR(N1), V1 , V2;
33                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_NCHAR(N1), V1 , V2;
34
35
36                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING N1, TO_NCHAR(V1) ,V2; 
37                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING N1, TO_NUMBER(V1) ,V2;    
38                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_CHAR(N1), TO_NCHAR(V1) , V2;  
39                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_CHAR(N1),TO_NUMBER(V1) ,V2; 
40                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_NCHAR(N1),TO_NCHAR(V1) ,V2; 
41                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_NCHAR(N1),TO_NUMBER(V1) ,V2;   
42
43
44
45                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING N1, V1 ,TO_CHAR(V2,'YYYY-MM-DD');
46                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING N1, V1,cast(V2 as timestamp);    
47                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING N1, TO_NUMBER(V1) ,TO_CHAR(V2,'YYYY-MM-DD'); 
48                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING N1, TO_NUMBER(V1) ,cast(V2 as timestamp);
49                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING N1, TO_CHAR(V1) ,TO_CHAR(V2,'YYYY-MM-DD'); 
50                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING N1, TO_CHAR(V1) ,cast(V2 as timestamp);
51                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING N1, TO_NCHAR(V1) ,TO_CHAR(V2,'YYYY-MM-DD'); 
52                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING N1, TO_NCHAR(V1) ,cast(V2 as timestamp);
53
54
55
56                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_CHAR(N1), V1 ,TO_CHAR(V2,'YYYY-MM-DD');
57                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_CHAR(N1), V1,cast(V2 as timestamp);    
58                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_CHAR(N1), TO_NUMBER(V1) ,TO_CHAR(V2,'YYYY-MM-DD'); 
59                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_CHAR(N1), TO_NUMBER(V1) ,cast(V2 as timestamp);
60                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_CHAR(N1), TO_CHAR(V1) ,TO_CHAR(V2,'YYYY-MM-DD'); 
61                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_CHAR(N1), TO_CHAR(V1) ,cast(V2 as timestamp);
62                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_CHAR(N1), TO_NCHAR(V1) ,TO_CHAR(V2,'YYYY-MM-DD'); 
63                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_CHAR(N1), TO_NCHAR(V1) ,cast(V2 as timestamp);
64
65
66                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_NCHAR(N1), V1 ,TO_CHAR(V2,'YYYY-MM-DD');
67                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_NCHAR(N1), V1,cast(V2 as timestamp);    
68                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_NCHAR(N1), TO_NUMBER(V1) ,TO_CHAR(V2,'YYYY-MM-DD'); 
69                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_NCHAR(N1), TO_NUMBER(V1) ,cast(V2 as timestamp);
70                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_NCHAR(N1), TO_CHAR(V1) ,TO_CHAR(V2,'YYYY-MM-DD'); 
71                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_CHAR(N1), TO_CHAR(V1) ,cast(V2 as timestamp);
72                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_NCHAR(N1), TO_NCHAR(V1) ,TO_CHAR(V2,'YYYY-MM-DD'); 
73                                EXECUTE IMMEDIATE 'INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)' USING TO_NCHAR(N1), TO_NCHAR(V1) ,cast(V2 as timestamp);        
74
75
76                     END; 
77
78         END LOOP; 
79
80         COMMIT;
81
82 end; 

查询游标情况:

1 select  address,hash_value,A.sql_profile,A.sql_plan_baseline,A.* from v$sql a where a.sql_text like '%INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES%' ;
2
3
4 select a.sql_id,A.child_number,a.bind_mismatch,a.BIND_LENGTH_UPGRADEABLE from v$sql_shared_cursor a where a.sql_id ='82hnj2bwpjj85';
5
6select a.sql_id,a.child_number,a.name,a.position,a.datatype_string,a.max_length from v$sql_bind_capture a where a.sql_id='610ygu94sf2t4' 
7 order by a.sql_id,a.child_number,a.position;
8
9
10  SELECT * FROM TABLE(VERSION_RPT('82hnj2bwpjj85'));  

大约生成90个子游标:

Oracle对索引做monitoring和nomonitoring会导致游标失效的实验-2

游标不能共享的原因:

Oracle对索引做monitoring和nomonitoring会导致游标失效的实验-3Oracle对索引做monitoring和nomonitoring会导致游标失效的实验-4

1Note:438755.1 Version Count Report Version 3.2.5 -- Today's Date 13-jun-24 14:13
2RDBMS Version :19.0.0.0.0 Host: lhrora19c Instance 1 : ORCLCDB
3==================================================================
4Addr: 0000000061FA5750  Hash_Value: 4183344389  SQL_ID 82hnj2bwpjj85
5Sharable_Mem: 1927358 bytes   Parses: 99000   Execs:99000
6Stmt: 
70 INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES(:N1,:V1,:V2)
81 
9
10Versions Summary
11----------------
12BIND_MISMATCH :89
13BIND_LENGTH_UPGRADEABLE :63
14
15Total Versions:89
16
17~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
18cursor_sharing = EXACT
19_cursor_obsolete_threshold = 8192 (See Note:10187168.8)
20~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
21
22Plan Hash Value Summary
23-----------------------
24Plan Hash Value Count
25=============== =====
26              0 90
27
28~~~~~~~~~~~~~~~~~~~~~~~~~~~
29Details for BIND_MISMATCH :
30
31Consolidated details for BIND* columns:
32BIND_MISMATCH,USER_BIND_PEEK_MISMATCH,BIND_UACS_DIFF,BIND_LENGTH_UPGRADEABLE,etc and
33BIND_EQUIV_FAILURE (Mislabled as ROW_LEVEL_SEC_MISMATCH BY bug 6964441 in 11gR1)
34
35from v$sql_bind_capture
36COUNT(*) POSITION MIN(MAX_LENGTH) MAX(MAX_LENGTH) DATATYPE BIND GRADUATION (PRECISION,SCALE)
37======== ======== =============== =============== ======== =============== =================
38      60        1              32              32        1     No           (,)
39      30        1              22              22        2     No           (,)
40      81        2              32            8192        1     Yes          (,)
41       9        2              22              22        2     No           (,)
42      30        3              32              32        1     No           (,)
43      30        3               7               7       12     No           (,)
44      30        3              11              11      180     No           (,9)
45
46SUM(DECODE(column,Y, 1, 0) FROM V$SQL
47IS_OBSOLETE IS_BIND_SENSITIVE IS_BIND_AWARE IS_SHAREABLE
48=========== ================= ============= ============
49          0                 0             0           27
50~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
51Details for BIND_LENGTH_UPGRADEABLE :
52
53Details shown already.
54####
55To further debug Ask Oracle Support for the appropiate level LLL.
56alter session set events 
57 'immediate trace name cursortrace address 4183344389, level LLL';
58To turn it off do use address 1, level 2147483648
59================================================================

接下来对游标做monitoring:

1SYS@ORCLCDB>  select  count(*) from v$sql a where a.sql_text like '%INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES%' and sql_id ='82hnj2bwpjj85'; 
2
3  COUNT(*)
4----------
5        90
6
7SYS@ORCLCDB> alter index idx_T_BG_20240613_LHR_02_N monitoring usage; 
8
9Index altered.
10
11SYS@ORCLCDB> col index_name format a60
12SYS@ORCLCDB> col table_name format a60
13SYS@ORCLCDB> SELECT * FROM V$OBJECT_USAGE a where a.index_name='IDX_T_BG_20240613_LHR_02_N'; 
14
15INDEX_NAME                                                   TABLE_NAME                                                   MONITO USED   START_MONITORING                       END_MONITORING
16------------------------------------------------------------ ------------------------------------------------------------ ------ ------ -------------------------------------- --------------------------------------
17IDX_T_BG_20240613_LHR_02_N                                   T_BG_20240613_LHR_02                                         YES    NO     06/13/2024 14:20:43
18
19SYS@ORCLCDB> 
20
21SYS@ORCLCDB>  select  count(*) from v$sql a where a.sql_text like '%INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES%' and sql_id ='82hnj2bwpjj85' and invalidations>0; 
22
23  COUNT(*)
24----------
25        90
26
27SYS@ORCLCDB> 

可以看到,在执行完monitoring后,90个子游标全部失效。

接下来再做一次最开始的begin块的插入操作,

1 begin     
2
3 。。。。。
4
5 end; 

插入完成后,再查询子游标个数:

1SYS@ORCLCDB>  select invalidations, count(*) from v$sql a where a.sql_text like '%INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES%' and sql_id ='82hnj2bwpjj85' group by invalidations; 
2
3INVALIDATIONS   COUNT(*)
4------------- ----------
5            1         90
6            0         63
7
8SYS@ORCLCDB> 

可以看到,又新增了63个子游标,

接下来对游标做nomonitoring:

1SYS@ORCLCDB>  alter index idx_T_BG_20240613_LHR_02_N nomonitoring usage; 
2
3Index altered.
4
5SYS@ORCLCDB>  SELECT * FROM V$OBJECT_USAGE a where a.index_name='IDX_T_BG_20240613_LHR_02_N'; 
6
7INDEX_NAME                                                   TABLE_NAME                                                   MONITO USED   START_MONITORING                       END_MONITORING
8------------------------------------------------------------ ------------------------------------------------------------ ------ ------ -------------------------------------- --------------------------------------
9IDX_T_BG_20240613_LHR_02_N                                   T_BG_20240613_LHR_02                                         NO     NO     06/13/2024 14:20:43                    06/13/2024 14:32:15
10
11SYS@ORCLCDB>  select invalidations, count(*) from v$sql a where a.sql_text like '%INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES%' and sql_id ='82hnj2bwpjj85' group by invalidations; 
12
13INVALIDATIONS   COUNT(*)
14------------- ----------
15            1        126
16            2         27
17
18SYS@ORCLCDB> 

可以看到,在执行完monitoring后,INVALIDATIONS为0的SQL语句没有了,说明游标全部失效。

接下来再做一次最开始的begin块的插入操作,然后再查询子游标数:

1SYS@ORCLCDB>  select invalidations, count(*) from v$sql a where a.sql_text like '%INSERT INTO T_BG_20240613_LHR_02(N,V,V2)  VALUES%' and sql_id ='82hnj2bwpjj85' group by invalidations; 
2
3INVALIDATIONS   COUNT(*)
4------------- ----------
5            1        126
6            2         27
7            0         63
8
9SYS@ORCLCDB> 
10SYS@ORCLCDB>  select a.version_count,a.invalidations from v$sqlarea a where a.sql_id      ='82hnj2bwpjj85';
11
12VERSION_COUNT INVALIDATIONS
13------------- -------------
14          216           180
15
16SYS@ORCLCDB> 

发现新增了63个子游标。

实验2

1CREATE TABLE lhr_table_temp (a VARCHAR2(4000));
2INSERT INTO lhr_table_temp (a)  VALUES ('test data session 1'); 
3commit;
4
5create index idx1 on lhr_table_temp(a);
6
7select * from lhr_table_temp;  --每轮执行5次
8select sql_text,sql_id,version_count,loads,invalidations,parse_calls from v$sqlarea a where sql_text  like '%select * from lhr_table_temp%';
9select a.executions,a.loads,a.sql_text,a.sql_id,a.first_load_time,a.last_load_time from v$sql a where sql_text like '%select * from lhr_table_temp%';
10
11alter index idx1 monitoring USAGE;
12alter index idx1 nomonitoring USAGE;
13
14
15SELECT * FROM V$OBJECT_USAGE;   

Oracle对索引做monitoring和nomonitoring会导致游标失效的实验-5

  1. loads为3表示加载了3次,即硬解析了3次,分别为建表后第1次查询,做monitoring后的查询,做nomonitoring后的查询

  2. invalidations为3表示游标失效了2次,因为做monitoring失效1次,做nomonitoring失效1次

  3. parse_calls可以认为每次硬解析后的执行次数

总结

1、对表上索引做“monitoring和nomonitoring会造成子游标失效”,在生产环境中,尤其是version_count很高的系统中,对核心生产业务表的DDL操作一定要慎重。

参考

https://www.dbaup.com/oraclezhilibrary-cachexiliedengdaishijianfenxifangfazongjiechixugengxin.html

https://www.dbaup.com/shenmeshigaobanbenyoubiaohigh-version-countruhepaicha.html

https://www.dbaup.com/kehumoutaooracle-racyewukuchuxianyanzhongdelibrary-cachedengdaipaicha.html

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论