Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
311 views

Wait Event - Latch: Row Cache Objects - DC - Objects

Oracle Wait Event - latch: row cache objects. Based on actual production DB wait event. Create test case to reproduce the wait event and detail cause of it.

Uploaded by

william_tang_45
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
311 views

Wait Event - Latch: Row Cache Objects - DC - Objects

Oracle Wait Event - latch: row cache objects. Based on actual production DB wait event. Create test case to reproduce the wait event and detail cause of it.

Uploaded by

william_tang_45
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 11

Wait Event - latch: row cache objects dc_objects

The following two experiments focus on wait event latch: row cache objects, on child latch# 9 dc_objects for database version 11.2.0.3 (In 10.2.0.4, this latch is dc_object_ids). The first experiment shows how concurrent sessions of hard parsing/optimizing with high number of dc_objects gets will cause wait event latch: row cache objects. The second experiment demonstrates the relationship between number of indexes in a table and number of gets on dc_objects when hard parsing/optimizing a sql.

Hard Parse and dc_objects Gets


Test DB is version: 11.2.0.3 with no CPU costing. db_block_size integer 8192 db_file_multiblock_read_count integer 8 optimizer_capture_sql_plan_baselines boolean FALSE Create test tables and generate data. SQL> @cr_t2.sql create table t2 ( c1 number not null, c2 number not null, c3 number not null, c4 number , c5 number , c6 number , c7 number , c8 number , c9 number , c10 number); Table created. /* Generate data */ SQL> @gen_data_t2.sql execute dbms_random.seed(0); PL/SQL procedure successfully completed.

William Tang

Page 1

insert into t2 select c1,c1+1,c1+2,c1+3,c1+4,c1+5,c1+6,c1+7,c1+8,c1+9 from ( select trunc(1+(100000-1)*dbms_random.value) c1 from (select rownum from all_objects where rownum <= 1000) k1, (select rownum from all_objects where rownum <= 100) k2 where rownum <=100000); 100000 rows created. commit; Commit complete. /* Generate creation of 100 indexes */ SQL> @gen_cr_t2_idx.sql with t2_cols as (select column_name from dba_tab_columns where table_name='T2'order by column_ID) select 'create index t2_idx'||rownum||' on t2('|| case when (tc1.column_name = tc2.column_name) then tc1.column_name else tc1.column_name||','||tc2.column_name end ||');' from t2_cols tc1, t2_cols tc2; create index t2_idx1 on t2(C1); create index t2_idx2 on t2(C1,C2); create index t2_idx3 on t2(C1,C3); create index t2_idx4 on t2(C1,C4); create index t2_idx5 on t2(C1,C5); create index t2_idx6 on t2(C1,C6); create index t2_idx7 on t2(C1,C7); create index t2_idx8 on t2(C1,C8); create index t2_idx9 on t2(C1,C9); create index t2_idx10 on t2(C1,C10); create index t2_idx11 on t2(C2,C1); create index t2_idx12 on t2(C2); ............ William Tang Page 2

create index t2_idx91 on t2(C10,C1); create index t2_idx92 on t2(C10,C2); create index t2_idx93 on t2(C10,C3); create index t2_idx94 on t2(C10,C4); create index t2_idx95 on t2(C10,C5); create index t2_idx96 on t2(C10,C6); create index t2_idx97 on t2(C10,C7); create index t2_idx98 on t2(C10,C8); create index t2_idx99 on t2(C10,C9); create index t2_idx100 on t2(C10); SQL> @cr_t2_idx.sql ..... Index created. SQL> Create table t3 same structure as t2(copied and modified t2 scripts). SQL> @cr_t3.sql Table created. /* execute dbms_random.seed(1); for t3 */ SQL> @gen_data_t3.sql PL/SQL procedure successfully completed.

100000 rows created.

Commit complete. SQL> @cr_t3_idx.sql ..... Index created. execute DBMS_STATS.gather_table_stats(ownname => 'WILLIAM', tabname => 'T2',estimate_percent => 100, DEGREE => 2); execute DBMS_STATS.gather_table_stats(ownname => 'WILLIAM', tabname => 'T3',estimate_percent => 100, DEGREE => 2); William Tang Page 3

--------------------------------------------------------------------------------------Generate hard parsing from 2 sessions to produce latch contention: Session 1: SQL> @gen_hp_t2.sql begin for i in 1 .. 29280 loop execute immediate 'SELECT count(*) FROM t2 WHERE rownum < '||i; end loop; end; / --------------------------------------------------------------------------------------Session 2: SQL> @gen_hp_t3.sql begin for i in 1 .. 29280 loop execute immediate 'SELECT count(*) FROM t3 WHERE rownum < '||i; end loop; end; / --------------------------------------------------------------------------------------Contention noticed in v$session_wait view: SID EVENT 12 latch: row cache objects 92 latch: row cache objects P1TEXT P1 P1RAW WAIT_CLASS address 6834553448 00000001975F0268 Concurrency address 6834553448 00000001975F0268 Concurrency

With child latch address 00000001975F0268, find out which child. SELECT child# FROM v$latch_children WHERE addr= '00000001975F0268'; CHILD# ---------9

William Tang

Page 4

/* Find out what row cache for child latch 9 */ select s.kqrstcln latch#, s.kqrstcid cache#, kqrsttxt name from x$kqrst s where s.kqrstcln=9; LATCH# CACHE# NAME ---------- ---------- -------------------------------9 8 dc_objects 9 8 dc_object_grants AWR report shows high gets on dc_objects. Why optimization could have cause high number of gets on this child latch? This leads us to second experiment which show number of indexes in a table contribute to high number of gets in dc_objects.

Indexes, Hard parse and dc_objects


The following script dc_objects_stat.sql will captured system statistics and dc_objects gets. One index will be dropped, and then a hard parse is generated every 1 second.
Create table to capture statistics. SQL> @row_cache_gets.sql William Tang Page 5

CREATE TABLE ROW_CACHE_GETS ( SDATE DATE, LGETS NUMBER, NINDEXES NUMBER ); Table created. Generate sql dc_objects_stat.sql (sql is in Addendum) and run it to capture statistics of dc_objects gets. SQL> @gen_stat_drop_idx.sql SQL> select count(*) from dba_indexes where table_name = 'T2'; COUNT(*) ---------100 SQL> alter system flush shared_pool; System altered. SQL> @dc_objects_stat.sql PL/SQL procedure successfully completed. SQL> select count(*) from dba_indexes where table_name = 'T2'; COUNT(*) ---------0 Run this sql to look at the statistics captured and create a graph with the data.
select rownum-1 "Interval(1 sec)", RC.* from (select sdate, case when (lgets >= nvl(lag(lgets) over (order by sdate), lgets)) then (lgets - nvl(lag(lgets) over (order by sdate), lgets)) else (lgets + 4294967296 - nvl(lag(lgets) over (order by sdate), lgets)) end "Gets", nindexes "Index counts" from row_cache_gets order by sdate ) RC;

William Tang

Page 6

This graph in figure 1 shows number of dc_objects gets during hard parse is directly proportional to number of indexes in table T2. As number of indexes decreased, so is number of gets. Figure 1:
7000 6000 5000 4000 3000 2000 1000 0 100 99 95 91 87 83 79 75 71 67 63 59 55 51 47 43 39 35 31 27 23 19 15 11 7 Index counts) Gets 3 0

So the more indexes in a table, higher number of dc_objects gets when hard parsing a sql. This will increase the likelihood of row cache latch contention when many sessions are hard parsing concurrently. But the graph cannot accurately represented by best fit line gets(x)=ax+b where x is index counts in a table. It seems at different range of index counts, we have different proportionality constants. Something else must contribute to dc_objects gets during optimization.

CBO index sorting


By default CBO uses index sorting as a tiebreaker method to choose the first index alphabetically in the event of a choice between two plans using indexes with equal costs. There is brief description in Oracle Doc ID 1485410.1 To demonstrate CBO index sorting contributes to dc_objects gets which in turn causes different proportionality constant at different range of index counts for figure 1, I will disable CBO index sorting by setting events 10089, level 1. Run the script dc_objects_stat.sql again to capture dc_objects gets statistics. Recreate indexes for table T2. SQL> @cr_t2_idx.sql SQL> truncate table row_cache_gets; Table truncated. William Tang Page 7

SQL> alter session set events '10089 trace name context forever, level 1'; Session altered. SQL> @read_event.sql Event 10089 set at level 1 PL/SQL procedure successfully completed. SQL> select count(*) from dba_indexes where table_name = 'T2'; COUNT(*) ---------100 SQL> alter system flush shared_pool; System altered. SQL> @dc_objects_stat.sql PL/SQL procedure successfully completed. SQL> select count(*) from dba_indexes where table_name = 'T2'; COUNT(*) ---------0 And the graph of statistics captured shows an accurate best fit line can be applied to it after disable CBO index sorting. Also, the number of dc_objects gets decreased substantially.

William Tang

Page 8

3000 2500 2000 1500 1000 500 0 100 98 93 88 83 78 73 68 63 58 53 48 43 38 33 28 23 18 13 Index counts Gets 8 3 0

Summary
We can limit latch contention on dc_object by minimize number of hard parse. In addition, minimize number of indexes created in a table, since number of dc_objects gets during hard parse or optimization is directly proportional to number of indexes in a table. Consider disable CBO index sorting, event 10089 to reduce number of dc_objects gets. If the sort order of indexes with CBO index sorting disable is different than default setting, setting event 10089 will affect sql plans using indexes with equal costs.

Addendum
/*gen_stat_drop_idx.sql*/ set feedback off set newpage none set termout off set head off set ver off set term off set line 100000 spool dc_objects_stat.sql select 'begin' from dual William Tang Page 9

union all select 'dbms_lock.sleep(1);'||chr(10)|| 'insert into row_cache_gets'||chr(10)|| '(SDATE,LGETS,NINDEXES)'||chr(10)|| 'select sysdate, a.gets,'||chr(10)|| 'i.idxcnt'||chr(10)|| 'from v$latch_children a,'||chr(10)|| '(select count(*) as idxcnt from dba_indexes where table_name = ''T2'') i'||chr(10)|| 'where a.name=''row cache objects'''||chr(10)|| 'and a.child#=9;'||chr(10)|| 'commit;'||chr(10)|| 'execute immediate ''SELECT count(*) FROM t2 '||chr(10)|| 'WHERE rownum <= '||rownum||''';' from dba_indexes where rownum <=3 union all select 'dbms_lock.sleep(1);'||chr(10)|| 'insert into row_cache_gets'||chr(10)|| 'select sysdate, a.gets,'||chr(10)|| 'i.idxcnt'||chr(10)|| 'from v$latch_children a,'||chr(10)|| '(select count(*) as idxcnt from dba_indexes where table_name = ''T2'') i'||chr(10)|| 'where a.name=''row cache objects'''||chr(10)|| 'and a.child#=9;'||chr(10)|| 'commit;'||chr(10)|| 'execute immediate ''drop index '||owner||'.'||index_name||''';'||chr(10)|| 'execute immediate ''SELECT count(*) FROM t2 '||chr(10)|| 'WHERE rownum <= '||rownum||'+3'';' from dba_indexes where table_name = 'T2' --and uniqueness != 'UNIQUE' --and index_name not like 'SYS_%' union all select 'dbms_lock.sleep(1);'||chr(10)|| 'insert into row_cache_gets'||chr(10)|| 'select sysdate, a.gets,'||chr(10)|| 'i.idxcnt'||chr(10)|| 'from v$latch_children a,'||chr(10)|| '(select count(*) as idxcnt from dba_indexes where table_name = ''T2'') i'||chr(10)|| 'where a.name=''row cache objects'''||chr(10)|| 'and a.child#=9;'||chr(10)|| 'commit;'||chr(10)|| 'execute immediate ''SELECT count(*) FROM t2 '||chr(10)|| 'WHERE rownum <= '||rownum||'+1000'';' William Tang Page 10

from dba_indexes where rownum <=3 union all select 'dbms_lock.sleep(1);'||chr(10)|| 'insert into row_cache_gets'||chr(10)|| 'select sysdate, a.gets,'||chr(10)|| 'i.idxcnt'||chr(10)|| 'from v$latch_children a,'||chr(10)|| '(select count(*) as idxcnt from dba_indexes where table_name = ''T2'') i'||chr(10)|| 'where a.name=''row cache objects'''||chr(10)|| 'and a.child#=9;'||chr(10)|| 'commit;'||chr(10)|| 'end;'||chr(10)||'/' from dual / spool off exit

William Tang

Page 11

You might also like