【IT168 技术文档】
继续前面的测试,这回测试RECYCLE池以及装满的情况下,查询还没有被CACHE的表的情况:
首先,清掉RECYCLE池。
SQL> ALTER TABLESPACE NDMAIN OFFLINE;
Tablespace altered.
SQL> ALTER TABLESPACE NDMAIN ONLINE;
Tablespace altered.
下面先把T放到RECYCLE池中:
SQL> SELECT COUNT(*) FROM T;
COUNT(*)
----------
334022
![]()
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
9667 consistent gets
9657 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', 'T3')
5 GROUP BY OBJECT_NAME, A.STATUS;
OBJECT_NAME STATU COUNT(*)
------------------------------ ----- ----------
T xcur 8096
SQL> SELECT COUNT(*) FROM T;
COUNT(*)
----------
334022
![]()
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
9667 consistent gets
1561 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
9667 consistent gets
1561 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表已经CACHE在RECYCLE中了,虽然T表比缓冲区大,但是由于RECYCLE的算法,保证大于缓存区大小的数据不会被缓存,因此,保证每次读取T表都会产生相同的物理读。
下面在缓存区满的情况下读取T2表到内存中:
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', 'T3')
5 GROUP BY OBJECT_NAME, A.STATUS;
OBJECT_NAME STATU COUNT(*)
------------------------------ ----- ----------
T xcur 8079
T2 xcur 17
可以发现,对于缓存区中不存在的表,Oracle是要将其放入到缓冲区的,这时候要把缓存中最后缓存的BLOCK替换出去。至于为什么是17个BLOCK,后面详细解释。
SQL> SELECT COUNT(*) FROM T3;
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', 'T3')
5 GROUP BY OBJECT_NAME, A.STATUS;
OBJECT_NAME STATU COUNT(*)
------------------------------ ----- ----------
T xcur 8078
T2 xcur 1
T3 xcur 17
在把T3表也放入到缓存中,同样Oracle发现T3没有在缓冲中,因此替换了最后进入到缓冲区的T2的16个BLOCK,并替换了T表最后被缓存的一个BLOCK。
Oracle这里之所以没有将T2表全部替换出去,就是为了在缓存中保留一份曾经进入过缓存的表的记录。而1个BLOCK是最小的保留数据。
回忆上一篇文章第一个例子中,T表的1个BLOCK始终没有被替换出去就是这个原因。
SQL> SELECT COUNT(*) FROM T3;
COUNT(*)
----------
167011
![]()
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
4839 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', 'T3')
5 GROUP BY OBJECT_NAME, A.STATUS;
OBJECT_NAME STATU COUNT(*)
------------------------------ ----- ----------
T xcur 8078
T2 xcur 1
T3 xcur 17
再次执行T3的扫描,发现T3的物理读是4828,在第一篇文章中已经知道,T3一共有4829个BLOCK,也就是说,这里只有第一个BLOCK被缓存。那么多出来的16个BLOCK是怎么产生的呢。
SQL> SHOW PARAMETER DB_FILE_MULTIBLOCK
NAME TYPE VALUE
------------------------------------ ----------- ---------------------
db_file_multiblock_read_count integer 16
由于初始化参数DB_FILE_MULTIBLOCK_READ_COUNT是16,因此,Oracle全表扫描的时候每次读取16个BLOCK。这16个BLOCK被用于存放每次读取的数据,来加速全表扫描的完成,因此这16个BLOCK应该是每次都被新的BLOCK替换出去。
简单总结一下:对于RECYCLE池,先装载的表保留在RECYCLE池中。RECYCLE池满了之后,读取的数据不被缓存。读取没有进入过RECYCLE池的表,会替换掉最后进入RECYCLE池的很少的BLOCK,而且,缓存的BLOCK也可能会很快被替换出去,但是最少会保留1个BLOCK在缓存中。