yangtingkun
===========================================================
CACHE和NOCACHE提示的进一步研究(一)
===========================================================

最近有个问题需要使用CACHE提示,于是简单研究了一下。偶然间发现自己前一阵写过一篇关于CACHENOCACHE提示的文章(自己都不记得了,汗),不过当时的结论不大准确,打算续一篇,将这次的测试结果补上。

这篇文章讨论NOCACHE提示。

其他相关文章:

CACHENOCACHE提示的进一步研究(一):http://yangtingkun.itpub.net/post/468/74472

以前的那篇文章:http://yangtingkun.itpub.net/post/468/30642


创建一个大表,用于清除缓冲区中的数据。

SQL> CREATE TABLE TEST AS SELECT * FROM DBA_SOURCE;

Table created.

SQL> INSERT INTO TEST SELECT * FROM TEST;

167011 rows created.

SQL> INSERT INTO TEST SELECT * FROM TEST;

334022 rows created.

SQL> INSERT INTO TEST SELECT * FROM TEST;

668044 rows created.

SQL> INSERT INTO TEST SELECT * FROM TEST;

1336088 rows created.

SQL> COMMIT;

Commit complete.

SQL> SELECT SUM(BYTES)/1024/1024/1024 GB FROM USER_SEGMENTS WHERE SEGMENT_NAME = 'TEST';

GB
----------
1.1875

SQL> SHOW PARAMETER DB_CACHE_SIZE

NAME TYPE VALUE
------------------------------------ ----------- ----------------------------
db_cache_size big integer 956301312

下面建立测试使用的表,表的大小应该比DB_CACHE_SIZE小。

SQL> CREATE TABLE TEST1 AS SELECT * FROM TEST WHERE ROWNUM < 1000000;

Table created.

SQL> SELECT SUM(BYTES)/1024/1024 MB FROM USER_SEGMENTS WHERE SEGMENT_NAME = 'TEST1';

MB
----------
456

建立两个测试使用的索引,为了在查询的时候可以使用索引,将索引列置为NOT NULL

SQL> CREATE INDEX IND_TEST_NAME ON TEST(NAME);

Index created.

SQL> CREATE INDEX IND_TEST1_NAME ON TEST1(NAME);

Index created.

SQL> ALTER TABLE TEST MODIFY NAME NOT NULL;

Table altered.

SQL> ALTER TABLE TEST1 MODIFY NAME NOT NULL;

Table altered.

下面开始NOCACHE提示的测试:

SQL> SET AUTOT ON
SQL> SELECT /*+ NOCACHE(TEST1) INDEX(TEST1) */ COUNT(TEXT) FROM TEST1;

COUNT(TEXT)
-----------
998500


Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=826 Card=1 Bytes=2002)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'TEST1' (Cost=826 Card=4737366 Bytes=9484206732)
3 2 INDEX (FULL SCAN) OF 'IND_TEST1_NAME' (NON-UNIQUE) (Cost=26 Card=4737366)

Statistics
----------------------------------------------------------
142 recursive calls
0 db block gets
41676 consistent gets
41636 physical reads
0 redo size
383 bytes sent via SQL*Net to client
503 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
4 sorts (memory)
0 sorts (disk)
1 rows processed

SQL> SELECT /*+ NOCACHE(TEST1) INDEX(TEST1) */ COUNT(TEXT) FROM TEST1;

COUNT(TEXT)
-----------
998500


Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=826 Card=1 Bytes=2002)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'TEST1' (Cost=826 Card=4737366 Bytes=9484206732)
3 2 INDEX (FULL SCAN) OF 'IND_TEST1_NAME' (NON-UNIQUE) (Cost=26 Card=4737366)

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
41659 consistent gets
41635 physical reads
0 redo size
383 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 /*+ NOCACHE(TEST1) INDEX(TEST1) */ COUNT(TEXT) FROM TEST1;

COUNT(TEXT)
-----------
998500


Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=826 Card=1 Bytes=2002)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'TEST1' (Cost=826 Card=4737366 Bytes=9484206732)
3 2 INDEX (FULL SCAN) OF 'IND_TEST1_NAME' (NON-UNIQUE) (Cost=26 Card=4737366)

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
41659 consistent gets
41635 physical reads
0 redo size
383 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

可以看到,使用了NOCACHE提示,索引扫描的块并没有被缓存,下面看看如果不加NOCACHE提示的效果:

SQL> SELECT /*+ INDEX(TEST1) */ COUNT(TEXT) FROM TEST1;

COUNT(TEXT)
-----------
998500


Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=826 Card=1 Bytes=2002)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'TEST1' (Cost=826 Card=4737366 Bytes=9484206732)
3 2 INDEX (FULL SCAN) OF 'IND_TEST1_NAME' (NON-UNIQUE) (Cost=26 Card=4737366)

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
41659 consistent gets
30561 physical reads
0 redo size
383 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 /*+ INDEX(TEST1) */ COUNT(TEXT) FROM TEST1;

COUNT(TEXT)
-----------
998500


Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=826 Card=1 Bytes=2002)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'TEST1' (Cost=826 Card=4737366 Bytes=9484206732)
3 2 INDEX (FULL SCAN) OF 'IND_TEST1_NAME' (NON-UNIQUE) (Cost=26 Card=4737366)

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
41659 consistent gets
0 physical reads
0 redo size
383 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

第二次执行的时候,发现所有的数据块都以及被缓存了。这说明NOCACHE提示是有作用的,而在我以前测试中犯了一个错误,因此得到了一个错误的结论。下面我们就来重现这个错误:

SQL> SELECT /*+ NOCACHE(TEST1) INDEX(TEST1) */ COUNT(TEXT) FROM TEST1;

COUNT(TEXT)
-----------
998500


Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=826 Card=1 Bytes=2002)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'TEST1' (Cost=826 Card=4737366 Bytes=9484206732)
3 2 INDEX (FULL SCAN) OF 'IND_TEST1_NAME' (NON-UNIQUE) (Cost=26 Card=4737366)

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
41659 consistent gets
0 physical reads
0 redo size
383 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 /*+ NOCACHE(TEST1) INDEX(TEST1) */ COUNT(TEXT) FROM TEST1;

COUNT(TEXT)
-----------
998500


Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=826 Card=1 Bytes=2002)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'TEST1' (Cost=826 Card=4737366 Bytes=9484206732)
3 2 INDEX (FULL SCAN) OF 'IND_TEST1_NAME' (NON-UNIQUE) (Cost=26 Card=4737366)

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
41659 consistent gets
0 physical reads
0 redo size
383 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

从当前的结果看,似乎这回NOCACHE提示没有起作用。但是提示操作只会针对当前的这次操作,它无法影响到数据库中以及缓存的数据。这两次执行的操作没有被缓存,可是这两次执行读取的数据块已经缓存是在内存中了。所以,NOCACHE提示就没有任何意义了,因为NOCACHE只能控制语句读取的数据块不送到内存中缓存,而没有办法将已经缓存的数据块清除出内存。这就是我前面那篇文章中测试时犯的错误。

另外,通过观察执行计划的改变,也可以看到NOCACHE实际上是在起作用的:

SQL> SELECT COUNT(*) FROM TEST1;

COUNT(*)
----------
999999


Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'TEST1'

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
28972 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

SQL> SELECT /*+ NOCACHE(TEST1) */ COUNT(*) FROM TEST1;

COUNT(*)
----------
999999


Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=1)
1 0 SORT (AGGREGATE)
2 1 INDEX (FAST FULL SCAN) OF 'IND_TEST1_NAME' (NON-UNIQUE) (Cost=4 Card=4737366)

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
1620 consistent gets
2 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

由于TEST1表没有进行分析,因此直接查询的时候使用了RBO,但是由于使用了提示,优化方式变成了CBO,而且自动选择了代价较小的索引快速扫描来替换了全表扫描。

yangtingkun 发表于:2006.04.25 18:37 ::分类: ( ORACLE ) ::阅读:(1528次) :: 评论 (0)

发表评论
标题

在此添加评论
表情符号: smile laughing tongue angry crying sad wassat wink

称呼

邮箱地址(可选)

个人主页(可选)

 authimage


切换风格
新闻聚合
博客日历
文章归档...
最新发表...
最新评论...
最多阅读文章...
最多评论文章...
博客统计...
Blog信息
网站链接...