合 Oracle 物理读、逻辑读、一致性读、当前模式读
在ORACLE数据库中有物理读(Physical Reads)、逻辑读(Logical Reads)、一致性读(Consistant Get)、当前模式读(DB Block Gets)等诸多概念,如果不理解或混淆这些概念的话,对你深入理解一些知识无疑是一个障碍,但是这些概念确实挺让让人犯晕的。下面我们总结、学习一下这方面的知识点。捋一捋他们的关系和特点,希望对你有所帮助。
物理读(Physical Reads)
从磁盘读取数据块到内存的操作叫物理读,当SGA里的高速缓存(Cache Buffer)里面不存在这些数据块时,就会产生物理读,另外。像全表扫描、磁盘排序等操作也可能产生物理读,原因也是因为ORACLE数据库需要访问的数据块较多,而有些数据块不在内存当中,需要从磁盘读取。
逻辑读(Logical Reads)
概念1:逻辑读指ORACLE从内存读到的数据块数量。一般来说, logical reads = db block gets + consistent gets
概念2:逻辑读指的就是从Buffer Cache中读取数据块。按照访问数据块的模式不同,可以分为当前模式读(Current Read)和一致性读(Consistent Read)。
这两个概念本质是一样的,只是措辞不一样。
一致性读(Consistant Get)
ORACLE是一个多用户系统。当一个会话开始读取数据还未结束读取之前,可能会有其他会话修改了它将要读取的数据。如果会话读取到修改后的数据,就会造成数据的不一致。一致性读就是为了保证数据的一致性。在Buffer Cache中的数据块上都会有最后一次修改数据块时的SCN。如果一个事务需要修改数据块中数据,会先在回滚段中保存一份修改前数据和SCN的数据块,然后再更新Buffer Cache中的数据块的数据及其SCN,并标识其为“脏”数据。当其他进程读取数据块时,会先比较数据块上的SCN和进程自己的SCN。如果数据块上的SCN小于等于进程本身的SCN,则直接读取数据块上的数据;如果数据块上的SCN大于进程本身的SCN,则会从回滚段中找出修改前的数据块读取数据。通常,普通查询都是一致性读。
当前模式读(DB Block Gets)
个人觉得当前模式读(db block gets)是最难理解的一个概念,通常情况下db block gets 可以理解为是DML操作才会产生的.
当前模式读(db block gets)即读取数据块是当前的最新数据。任何时候在Buffer Cache中都只有一份当前数据块。当前读通常发生在对数据进行修改、删除操作时。这时,进程会给数据加上行级锁,并且标识数据为“脏”数据。current mode产生db block gets,一般在DML操作时产生,query mode产生consistent gets(一致性读),一般在查询时产生。他们两个总和一般称为逻辑读,logical read。
有个有意思的现象,在ask tom或一些资料中,你会发现Oracle 8i在SELECT查询当中还能看到db block gets,但是ORACLE 10以及以上版本在SELECT语句中db block gets一般为0。
了解完了概念,如果你还是有一些疑问和不解,那我们结合实际例子来理解一下这些概念吧。如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | SQL> show user; USER is "SYS" SQL> create table test 2 as 3 select * from dba_objects; Table created. SQL> alter session set sql_trace=true; System altered. SQL> set autotrace on; SQL> select object_type, count(1) from test 2 group by object_type; OBJECT_TYPE COUNT(1) ------------------- ---------- EDITION 1 INDEX PARTITION 264 CONSUMER GROUP 25 SEQUENCE 223 TABLE PARTITION 240 SCHEDULE 3 QUEUE 35 RULE 1 JAVA DATA 328 ............................... ............................... 43 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 1435881708 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 75101 | 806K| 284 (2)| 00:00:04 | | 1 | HASH GROUP BY | | 75101 | 806K| 284 (2)| 00:00:04 | | 2 | TABLE ACCESS FULL| TEST | 75101 | 806K| 281 (1)| 00:00:04 | --------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement (level=2) Statistics ---------------------------------------------------------- 48 recursive calls 0 db block gets 1109 consistent gets 1029 physical reads 0 redo size 1694 bytes sent via SQL*Net to client 545 bytes received via SQL*Net from client 4 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 43 rows processed SQL> select object_type, count(1) from test 2 group by object_type; OBJECT_TYPE COUNT(1) ------------------- ---------- EDITION 1 INDEX PARTITION 264 CONSUMER GROUP 25 SEQUENCE 223 TABLE PARTITION 240 .............................. .............................. 43 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 1435881708 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 75101 | 806K| 284 (2)| 00:00:04 | | 1 | HASH GROUP BY | | 75101 | 806K| 284 (2)| 00:00:04 | | 2 | TABLE ACCESS FULL| TEST | 75101 | 806K| 281 (1)| 00:00:04 | --------------------------------------------------------------------------- Note ----- - dynamic sampling used for this statement (level=2) Statistics ---------------------------------------------------------- 0 recursive calls 0 db block gets 1034 consistent gets 0 physical reads 0 redo size 1694 bytes sent via SQL*Net to client 545 bytes received via SQL*Net from client 4 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 43 rows processed SQL> set autotrace off SQL> alter session set sql_trace =false; Session altered. SQL> SELECT T.value 2 || '/' 3 || Lower(Rtrim(I.INSTANCE, Chr(0))) 4 || '_ora_' 5 || P.spid 6 || '.trc' TRACE_FILE_NAME 7 FROM (SELECT P.spid 8 FROM v$mystat M, 9 v$session S, 10 v$process P 11 WHERE M.statistic# = 1 12 AND S.sid = M.sid 13 AND P.addr = S.paddr) P, 14 (SELECT T.INSTANCE 15 FROM v$thread T, 16 v$parameter V 17 WHERE V.name = 'thread' 18 AND ( V.value = 0 19 OR T.thread# = To_number(V.value) )) I, 20 (SELECT value 21 FROM v$parameter 22 WHERE name = 'user_dump_dest') T; TRACE_FILE_NAME -------------------------------------------------------------------------------- /u01/app/oracle/diag/rdbms/gsp/gsp/trace/gsp_ora_24900.trc |
如上截图所示, SQL语句第一次执行时,一致性读(consistent gets)为1109, 物理读(physical reads)为1029,当前模式读(db block gets)为0. 如果你再执行一次上面SQL语句,你会发现物理读(physical reads)会降低为0了,因为上一次查询,ORACLE已经将表test的所有数据块读取到buffer cache里面了。当然生产环境实际情况会复杂很多。
我们先用tkprof工具格式化一下trace文件,然后我们分析一下 out_24900.prf文件。
[oracle@DB-Server trace]$ tkprof gsp_ora_24900.trc out_24900.prf aggregate=no;
TKPROF: Release 11.2.0.1.0 - Development on Thu Sep 22 10:12:15 2016
Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
在分析之前,我们先了解一下一些概念、术语
count = number of times OCI procedure was executed
cpu = cpu time in seconds executing
elapsed = elapsed time in seconds executing