关于consistent gets(r5笔记第12天)

时间:2022-05-04
本文章向大家介绍关于consistent gets(r5笔记第12天),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

在sql调优的时候,一个关键指标就是consistent gets,如果这个指标很低,一般认为sql语句执行还是很高效的,反之效率会很低。但是这个指标我们知之甚少,对于这个指标的计算方式我们也是懵懵懂懂。对于逻辑读来说,一般都是基于Logical Reads= Consistent Gets + DB Block Gets 如果我们知道logical reads是1000,我们可能错误地认为查询读取了1000*8k(约为8M) 看了博客https://viveklsharma.wordpress.com/2010/03/04/consistent-gets-myth/后,发现自己的认识是错误的,也按捺不住在本地测试了一把,受益匪浅。 首先我们来创建一个表,数据量为2000条。 n1@TEST11G> create table test_consistent_get as select * from all_objects where rownum between 1 and 2000; Table created. 然后收集统计信息 n1@TEST11G> exec dbms_stats.gather_table_stats(user,'TEST_CONSISTENT_GET'); PL/SQL procedure successfully completed. 查看相应的数据块为30个 n1@TEST11G> select num_rows,blocks,table_name,last_analyzed,global_stats from user_tables where table_name='TEST_CONSISTENT_GET'; NUM_ROWS BLOCKS TABLE_NAME LAST_ANAL GLO ---------- ---------- ------------------------------ --------- --- 2000 30 TEST_CONSISTENT_GET 20-APR-15 YES n1@TEST11G> set autot trace 我们来看看执行计划,很明显走了一个全表扫描。但是我们需要关注的是统计信息中的consistent gets n1@TEST11G> select * from test_consistent_get; Execution Plan ---------------------------------------------------------- Plan hash value: 1444268095 ----------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ----------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 2000 | 164K| 10 (0)| 00:00:01 | | 1 | TABLE ACCESS FULL| TEST_CONSISTENT_GET | 2000 | 164K| 10 (0)| 00:00:01 | ----------------------------------------------------------------------------------------- Statistics ---------------------------------------------------------- 1 recursive calls 0 db block gets 163 consistent gets 0 physical reads 0 redo size 199754 bytes sent via SQL*Net to client 1883 bytes received via SQL*Net from client 135 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 2000 rows processed 可以看到这个表占用的数据块为30,但是consistent gets却为163,很显然不是说这个全表扫描向cache里读入了163*8k的数据 我们可以通过rowid来得到对应的数据块和其中的数据情况 n1@TEST11G> select dbms_rowid.ROWID_BLOCK_NUMBER(rowid) blkno, count(*) cnt from test_consistent_get group by dbms_rowid.ROWID_BLOCK_NUMBER(rowid) order by 1; BLKNO CNT ---------- ---------- 263827 88 263828 84 263829 81 263830 76 263831 81 263832 80 263833 82 263834 77 263835 73 263836 78 263837 79 263838 79 263839 81 263841 82 263842 77 263843 81 263844 80 263845 81 263846 78 263847 78 263848 76 263849 78 263850 78 263851 76 263852 81 263853 15 26 rows selected. 可以通过rowid得到相关的数据块为26个。查看段头,发现对应的数据块是263826是不在上面的rowid对应的数据块范围内的。 n1@TEST11G> select header_block,blocks ,extents from dba_segments where segment_name='TEST_CONSISTENT_GET'; HEADER_BLOCK BLOCKS EXTENTS ------------ ---------- ---------- 263826 32 4 对应的区和数据块信息如下: n1@TEST11G> select EXTENT_ID, FILE_ID, BLOCK_ID, BLOCKS from dba_extents where SEGMENT_NAME='TEST_CONSISTENT_GET'; EXTENT_ID FILE_ID BLOCK_ID BLOCKS ---------- ---------- ---------- ---------- 0 4 263824 8 1 4 263832 8 2 4 263840 8 3 4 263848 8 下面的语句可以算出对于每个数据块对应的consistent gets的值。 n1@TEST11G> variable b1 number; exec :b1:=15; compute sum of total_cnt on report compute sum of touch_cnt on report break on report select blkno, total_cnt, final_cnt, rows_remaining, case when rows_remaining=0 then touch_cnt+1 else touch_cnt end touch_cnt from ( select blkno, total_cnt, final_cnt, rows_remaining, case when total_cnt = final_cnt then ceil(final_cnt/:b1) else ceil(final_cnt/:b1)+1 end touch_cnt from ( select blkno, cnt total_cnt, case when rownum=1 or lag(rows_remaining) over (order by blkno)=0 then cnt else (cnt-(:b1-lag(rows_remaining) over (order by blkno))) end final_cnt, rows_remaining from ( select blkno, cnt, rr, lead(rr) over(order by blkno) next_rr, lead(blkno) over(order by blkno) next_blk, ceil(rr/:b1) touch_cnt, mod(rr,:b1) rows_remaining from ( select dbms_rowid.ROWID_BLOCK_NUMBER(rowid) blkno, count(*) cnt, sum(count(*)) over(order by dbms_rowid.ROWID_BLOCK_NUMBER(rowid)) rr from test_consistent_get group by dbms_rowid.ROWID_BLOCK_NUMBER(rowid) order by 1)))); BLKNO TOTAL_CNT FINAL_CNT ROWS_REMAINING TOUCH_CNT ---------- ---------- ---------- -------------- ---------- 263827 88 88 13 6 263828 84 82 7 7 263829 81 73 13 6 263830 76 74 14 6 263831 81 80 5 7 263832 80 70 10 6 263833 82 77 2 7 263834 77 64 4 6 263835 73 62 2 6 263836 78 65 5 6 263837 79 69 9 6 263838 79 73 13 6 263839 81 79 4 7 263841 82 71 11 6 263842 77 73 13 6 263843 81 79 4 7 263844 80 69 9 6 263845 81 75 0 7 263846 78 78 3 6 263847 78 66 6 6 263848 76 67 7 6 263849 78 70 10 6 263850 78 73 13 6 263851 76 74 14 6 263852 81 80 5 7 263853 15 5 5 2 ---------- ---------- sum 2000 159 可以看到对于这个全表扫描的场景,consistent gets不是衡量对于cache的数据块数而是次数。 比如对于上面的数据块263827 ,数据条数为88条,arraysize为15,则可以简单说明一下是如何计算这个consistent gets值的。 对于数据块263827,放入PGA中,得到了15行,这个时候可以理解为consistent gets=1 对于数据块263827,再次从PGA中得到,得到了15行,这个时候consistent gets=2 依次类推 对于数据块263827,再次从PGA中得到,得到了13行,这个时候consistent gets=6 或者也可以基本按照这个公式来计算,数据行数/数据块数+数据块数=consistent gets 比如这个例子,2000/15+30 大概是163.3左右,所以163还是靠谱的。 对于arraysize未20,30,的情况下,相应的consistent gets也会减少。简单模拟一下。 n1@TEST11G> set arraysize 20 n1@TEST11G> set autot trace exp stat n1@TEST11G> select *from test_consistent_get; Statistics ---------------------------------------------------------- 1 recursive calls 0 db block gets 128 consistent gets 0 physical reads 0 redo size 195334 bytes sent via SQL*Net to client 1509 bytes received via SQL*Net from client 101 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 2000 rows processed n1@TEST11G> set autot off n1@TEST11G> select 2000/20+30 from dual; 2000/20+30 ---------- 130 n1@TEST11G> set arraysize 30 n1@TEST11G> set autot trace stat n1@TEST11G> select *from test_consistent_get; Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 96 consistent gets 0 physical reads 0 redo size 191044 bytes sent via SQL*Net to client 1146 bytes received via SQL*Net from client 68 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 2000 rows processed n1@TEST11G> set autot off n1@TEST11G> select 2000/30+30 from dual; 2000/30+30 ---------- 96.6666667