direct path read新特性导致buffer_pool keep失效

最近朋友遇到一个问题,有个表迁到11g后,之前设置buffer_pool keep失效了,每次查询都有很大的物理读
经过检查发现是11g的新特性direct path read导致的
这个特性其实就是oracle在扫描一个大表的时候,会将数据直接读取到pga中,而不经过sga,所以就造成了buffer_pool keep没有生效的问题
oracle通过参数_small_table_threshold 来评估一个表是大表还是小表,单位是块,大于这个值的表,oracle就认为是大表

下面我们模拟一下这种情况
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
PL/SQL Release 11.2.0.1.0 - Production
CORE    11.2.0.1.0      Production
TNS for Linux: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production
SQL> create table goolen as select * from dba_objects;
Table created.
SQL> alter table scott.goolen storage(buffer_pool keep);
Table altered.
SQL> insert into goolen select * from goolen;
SQL> /
/....
--这个sql可以查看buffer_cache中的缓存对象
SQL> SELECT o.object_name, COUNT(1) number_of_blocks 
  2  FROM DBA_OBJECTS o, V$BH bh                   
  3  WHERE o.object_id  = bh.objd                   
  4  AND o.owner != 'SYS'
  5  group by o.object_name                
  6  ORDER BY count(1);
OBJECT_NAME                         NUMBER_OF_BLOCKS
----------------------------------- ----------------
GOOLEN                                         31560
--查看参数_small_table_threshold的值
SQL> col name for a30
SQL> col value for a20
SQL> col DESCRIB for a60
SQL> set linesize 140 pagesize 1400
SQL>  
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
  2  FROM SYS.x$ksppi x, SYS.x$ksppcv y
  3  WHERE x.inst_id = USERENV ('Instance')
  4  AND y.inst_id = USERENV ('Instance')
  5  AND x.indx = y.indx
  6  AND (x.ksppinm ='_small_table_threshold'or x.ksppinm='_serial_direct_read');
NAME                           VALUE                DESCRIB
------------------------------ -------------------- ------------------------------------------------------------
_small_table_threshold         500                 lower threshold level of table size for direct reads
_serial_direct_read            FALSE                enable direct read in serial

SQL> alter system flush buffer_cache;
SQL> select count(*) from goolen;
  COUNT(*)
----------
   1155424
Execution Plan
----------------------------------------------------------
Plan hash value: 1270414684
---------------------------------------------------------------------
| Id  | Operation          | Name   | Rows  | Cost (%CPU)| Time     |
---------------------------------------------------------------------
|   0 | SELECT STATEMENT   |        |     1 |  4771   (2)| 00:00:58 |
|   1 |  SORT AGGREGATE    |        |     1 |            |          |
|   2 |   TABLE ACCESS FULL| GOOLEN |    19M|  4771   (2)| 00:00:58 |
---------------------------------------------------------------------
Note
-----
   - dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      16499  consistent gets
      16489  physical reads
          0  redo size
        529  bytes sent via SQL*Net to client
        524  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 goolen;
  COUNT(*)
----------
   1155424
Execution Plan
----------------------------------------------------------
Plan hash value: 1270414684
---------------------------------------------------------------------
| Id  | Operation          | Name   | Rows  | Cost (%CPU)| Time     |
---------------------------------------------------------------------
|   0 | SELECT STATEMENT   |        |     1 |  4771   (2)| 00:00:58 |
|   1 |  SORT AGGREGATE    |        |     1 |            |          |
|   2 |   TABLE ACCESS FULL| GOOLEN |    19M|  4771   (2)| 00:00:58 |
---------------------------------------------------------------------
Note
-----
   - dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      16499  consistent gets
      16489  physical reads
          0  redo size
        529  bytes sent via SQL*Net to client
        524  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
--每次查询都有很大的物理读

--我们用10046事件跟踪一下这个sql
SQL> oradebug setmypid
Statement processed.
SQL> oradebug tracefile_name
/opt/app/oracle/diag/rdbms/goolen/goolen/trace/goolen_ora_2194.trc
SQL> alter session set events '10046 trace name context forever,level 8';
Session altered.
SQL> select count(*) from scott.goolen;
  COUNT(*)
----------
   1155424
--查看trace文件发现wait都是direct path read
=====================
PARSING IN CURSOR #2 len=33 dep=0 uid=0 oct=3 lid=0 tim=1382688719747413 hv=1981856655 ad='db29f650' sqlid='4ub9jxdv21fwg'
select count(*) from scott.goolen
END OF STMT
PARSE #2:c=8998,e=9807,p=270,cr=72,cu=0,mis=1,r=0,dep=0,og=1,plh=1270414684,tim=1382688719747412
EXEC #2:c=0,e=34,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1270414684,tim=1382688719747526
WAIT #2: nam='SQL*Net message to client' ela= 2 driver id=1650815232 #bytes=1 p3=0 obj#=5352 tim=1382688719747576
WAIT #2: nam='direct path read' ela= 128 file number=4 first dba=171 block cnt=13 obj#=74754 tim=1382688719748396
WAIT #2: nam='direct path read' ela= 138 file number=4 first dba=185 block cnt=15 obj#=74754 tim=1382688719748590
WAIT #2: nam='direct path read' ela= 64 file number=4 first dba=201 block cnt=15 obj#=74754 tim=1382688719748779
WAIT #2: nam='direct path read' ela= 52 file number=4 first dba=217 block cnt=15 obj#=74754 tim=1382688719748954
WAIT #2: nam='direct path read' ela= 52 file number=4 first dba=233 block cnt=15 obj#=74754 tim=1382688719749128
WAIT #2: nam='direct path read' ela= 53 file number=4 first dba=249 block cnt=15 obj#=74754 tim=1382688719749305
WAIT #2: nam='direct path read' ela= 62 file number=4 first dba=265 block cnt=15 obj#=74754 tim=1382688719749488
WAIT #2: nam='direct path read' ela= 52 file number=4 first dba=281 block cnt=15 obj#=74754 tim=1382688719749660
WAIT #2: nam='direct path read' ela= 1069 file number=4 first dba=386 block cnt=126 obj#=74754 tim=1382688719750861
WAIT #2: nam='direct path read' ela= 1058 file number=4 first dba=514 block cnt=126 obj#=74754 tim=1382688719752056
WAIT #2: nam='direct path read' ela= 411 file number=4 first dba=642 block cnt=126 obj#=74754 tim=1382688719753315
WAIT #2: nam='direct path read' ela= 421 file number=4 first dba=770 block cnt=126 obj#=74754 tim=1382688719754560
WAIT #2: nam='direct path read' ela= 413 file number=4 first dba=898 block cnt=126 obj#=74754 tim=1382688719755788
WAIT #2: nam='direct path read' ela= 405 file number=4 first dba=1026 block cnt=126 obj#=74754 tim=1382688719757010
WAIT #2: nam='direct path read' ela= 400 file number=4 first dba=1154 block cnt=126 obj#=74754 tim=1382688719758225
WAIT #2: nam='direct path read' ela= 416 file number=4 first dba=1282 block cnt=126 obj#=74754 tim=1382688719759478
WAIT #2: nam='direct path read' ela= 410 file number=4 first dba=1410 block cnt=126 obj#=74754 tim=1382688719760723

--我们可以通过调大此参数的值,来避免oracle将这个表视为大表
SQL> alter session set "_small_table_threshold"=9999999;
Session altered.
--当然也可以通过设置10949事件来禁止这个特性
-- ALTER SESSION SET EVENTS '10949 TRACE NAME CONTEXT FOREVER';
SQL> select count(*) from goolen;
  COUNT(*)
----------
   1155424
SQL> set autot on
SQL> select count(*) from goolen;
  COUNT(*)
----------
   1155424
Execution Plan
----------------------------------------------------------
Plan hash value: 1270414684
--------------------------------------------------------------------
| Id  | Operation          | Name   | Rows  | Cost (%CPU)| Time     |
---------------------------------------------------------------------
|   0 | SELECT STATEMENT   |        |     1 |  4771   (2)| 00:00:58 |
|   1 |  SORT AGGREGATE    |        |     1 |            |          |
|   2 |   TABLE ACCESS FULL| GOOLEN |    19M|  4771   (2)| 00:00:58 |
---------------------------------------------------------------------
Note
-----
   - dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      16506  consistent gets
          0  physical reads
          0  redo size
        529  bytes sent via SQL*Net to client
        524  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 goolen;
  COUNT(*)
----------
   1155424
Execution Plan
----------------------------------------------------------
Plan hash value: 1270414684
---------------------------------------------------------------------
| Id  | Operation          | Name   | Rows  | Cost (%CPU)| Time     |
---------------------------------------------------------------------
|   0 | SELECT STATEMENT   |        |     1 |  4771   (2)| 00:00:58 |
|   1 |  SORT AGGREGATE    |        |     1 |            |          |
|   2 |   TABLE ACCESS FULL| GOOLEN |    19M|  4771   (2)| 00:00:58 |
---------------------------------------------------------------------
Note
-----
   - dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      16506  consistent gets
          0  physical reads
          0  redo size
        529  bytes sent via SQL*Net to client
        524  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)

          1  rows processed



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值