技术开发 频道

KEEP池的CACHE特点(二)

【IT168 技术文档】
 
上一篇文章介绍了KEEP池和DEFAULT池的差异之处,下面通过例子进行详细的说明:

首先,将T表的容量扩大1倍,这样,即使是单独查询T表,所有的数据也无法全部放入KEEP池。
SQL> INSERT INTO T SELECT * FROM T; 167011 rows created. SQL> COMMIT; Commit complete. SQL> SELECT COUNT(*) FROM T; COUNT(*) ---------- 334022 Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 9666 consistent gets 4828 physical reads 0 redo size 381 bytes sent via SQL*Net to client 503 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed SQL> SELECT OBJECT_NAME, A.STATUS, COUNT(*) 2 FROM V$BH A, USER_OBJECTS B 3 WHERE A.OBJD = B.OBJECT_ID 4 AND OBJECT_NAME IN ('T', 'T2') 5 GROUP BY OBJECT_NAME, A.STATUS; OBJECT_NAME STATU COUNT(*) ------------------------------ ----- ---------- T xcur 8097 SQL> SELECT SUM(BLOCKS) FROM USER_EXTENTS WHERE SEGMENT_NAME = 'T'; SUM(BLOCKS) ----------- 9728
可以看到T表一共是9728BLOCK,而KEEP池中仅仅缓存了8097个。
SQL> SHOW PARAMETER DB_BLOCK_SIZE NAME TYPE VALUE ------------------------------------ ----------- --------------------- db_block_size integer 16384
KEEP池的大小是128M,除以数据块的大小16KKEEP池中可以存放的BLOCK上限就是8K个。现在KEEP池已经装满,但是仍然有部分数据被替换到KEEP池外。

下面说明KEEP池缓存的特点,先看一下查询的结果:
SQL> SELECT COUNT(*) FROM T2; COUNT(*) ---------- 167011 Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 4839 consistent gets 4829 physical reads 0 redo size 381 bytes sent via SQL*Net to client 503 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed SQL> SELECT OBJECT_NAME, A.STATUS, COUNT(*) 2 FROM V$BH A, USER_OBJECTS B 3 WHERE A.OBJD = B.OBJECT_ID 4 AND OBJECT_NAME IN ('T', 'T2') 5 GROUP BY OBJECT_NAME, A.STATUS; OBJECT_NAME STATU COUNT(*) ------------------------------ ----- ---------- T xcur 3268 T2 xcur 4829 SQL> SELECT COUNT(*) FROM T; COUNT(*) ---------- 334022 Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 9666 consistent gets 9655 physical reads 0 redo size 381 bytes sent via SQL*Net to client 503 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed
对于第一个查询全部物理读比较好理解,这是由于当时KEEP池中的空间被T表占满了,隐藏这时候对T2的查询需要从物理磁盘读取。执行完这个查询,可以发现,T2表全部放入缓存中,T表的数据被替换出一部分,还有3000多个BLOCK存储在KEEP池中。但是对T的查询确全部由物理读组成,而KEEP池中的缓存没有起作用。

对于普通的DEFAULT池,Oracle使用的是最近最少使用算法,在内存中有一个类似链表的结构。当DB_CACHE填满后,Oracle会从将这个链表的最少使用端交换出去,用来存放新的数据。而且会根据新的数据的性质,选择把新的数据放到最多使用端还是最少使用端。

如果DB_CACHE满后,执行的是索引扫描,则Oracle认为需要缓存这些数据,因此会清空最少使用端的空间,存放索引扫描的缓存数据。如果是大表的全表扫描,则Oracle认为这些数据是很少需要被访问的,因此清空最少使用端的空间放入表扫描的缓存数据后,仍然放回到最少使用端。

KEEP池没有采用这种算法,KEEP池其实是一块可用内存采用类似循环的算法进行访问。如果KEEP池里面还有剩余空间,则新的数据会首先使用剩余的空间,如果KEEP池已经存储满了,Oracle会从头开始重用KEEP池。

这就是对T表的查询导致了全部的物理读的原因。由于T2表将T表中最初部分数据替换出KEEP,导致了查询T表的时候,开头部分的数据无法找到,产生了物理读后在KEEP池中替换了T表中间部分的数据,同样的道理,读取到T表中部的时候,又把T表末尾的数据替换出去了。因此,执行完查询发现,对T表查询全部都是物理读,KEEP池缓冲中的内容没有起作用。

而且,由于T表的大小超过了KEEP池的大小,因此T表末尾部分的数据又会将开头部分的数据替换出去,因此,再次对T表查询仍然全部都是物理读。
SQL> SELECT COUNT(*) FROM T; COUNT(*) ---------- 334022 Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 9666 consistent gets 9655 physical reads 0 redo size 381 bytes sent via SQL*Net to client 503 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed SQL> SELECT COUNT(*) FROM T; COUNT(*) ---------- 334022 Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 9666 consistent gets 9655 physical reads 0 redo size 381 bytes sent via SQL*Net to client 503 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed
    只有当对T表的扫描的块小于KEEP池的大小时,才能保证缓存可以被利用。
SQL> SELECT COUNT(*) FROM T WHERE ROWNUM < 100000; COUNT(*) ---------- 99999 Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 3696 consistent gets 3695 physical reads 0 redo size 381 bytes sent via SQL*Net to client 503 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed SQL> SELECT COUNT(*) FROM T WHERE ROWNUM < 100000; COUNT(*) ---------- 99999 Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 3696 consistent gets 0 physical reads 0 redo size 381 bytes sent via SQL*Net to client 503 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed
0
相关文章