Oracle 物理讀 邏輯讀 一致性讀 當前模式讀總結淺析

Oracle 物理讀 邏輯讀 一致性讀 當前模式讀總結淺析

  在ORACLE數據庫中有物理讀(Physical Reads)、邏輯讀(Logical Reads)、一致性讀(Consistant Get)、當前模式讀(DB Block Gets)等諸多概念,若是不理解或混淆這些概念的話,對你深刻理解一些知識無疑是一個障礙,可是這些概念確實挺讓讓人犯暈的。下面咱們總結、學習一下這方面的知識點。捋一捋他們的關係和特色,但願對你有所幫助。 sql

 

物理讀(Physical Reads) 數據庫

 

從磁盤讀取數據塊到內存的操做叫物理讀,當SGA裏的高速緩存(Cache Buffer)裏面不存在這些數據塊時,就會產生物理讀,另外。像全表掃描、磁盤排序等操做也可能產生物理讀,緣由也是由於ORACLE數據庫須要訪問的數據塊較多,而有些數據塊不在內存當中,須要從磁盤讀取。 編程

 

邏輯讀(Logical Reads) c#

 

概念1:邏輯讀指ORACLE從內存讀到的數據塊數量。通常來講, logical reads = db block gets + consistent gets 緩存

概念2:邏輯讀指的就是從Buffer Cache中讀取數據塊。按照訪問數據塊的模式不一樣,能夠分爲當前模式讀(Current Read)和一致性讀(Consistent Read)。  session

這兩個概念本質是同樣的,只是措辭不同。 oracle

 

一致性讀(Consistant Get) app

 

ORACLE是一個多用戶系統。當一個會話開始讀取數據還未結束讀取以前,可能會有其餘會話修改了它將要讀取的數據。若是會話讀取到修改後的數據,就會形成數據的不一致。一致性讀就是爲了保證數據的一致性。在Buffer Cache中的數據塊上都會有最後一次修改數據塊時的SCN。若是一個事務須要修改數據塊中數據,會先在回滾段中保存一份修改前數據和SCN的數據塊,而後再更新Buffer Cache中的數據塊的數據及其SCN,並標識其爲「髒」數據。當其餘進程讀取數據塊時,會先比較數據塊上的SCN和進程本身的SCN。若是數據塊上的SCN小於等於進程自己的SCN,則直接讀取數據塊上的數據;若是數據塊上的SCN大於進程自己的SCN,則會從回滾段中找出修改前的數據塊讀取數據。一般,普通查詢都是一致性讀。 ide

 

當前模式讀(DB Block Gets) wordpress

 

我的以爲當前模式讀(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。

瞭解完了概念,若是你仍是有一些疑問和不解,那咱們結合實際例子來理解一下這些概念吧。以下所示:

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

clip_image001

 

如上截圖所示, SQL語句第一次執行時,一致性讀(consistent gets)爲1109, 物理讀(physical reads)爲1029,當前模式讀(db block gets)爲0. 若是你再執行一次上面SQL語句,你會發現物理讀(physical reads)會下降爲0了,由於上一次查詢,ORACLE已經將表test的全部數據塊讀取到buffer cache裏面了。固然生產環境實際狀況會複雜不少。

 

clip_image002

 

咱們先用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

disk     = number of physical reads of buffers from disk                   物理讀

query    = number of buffers gotten for consistent read                    一致性讀

current  = number of buffers gotten in current mode (usually for update)   當前模式讀

rows     = number of rows processed by the fetch or execute call

 

 

call:每次SQL語句的處理都分紅三個部分

 

    Parse:這步包括語法檢查和語義檢查(包括檢查是否有正確的受權和所須要用到的表、列以及其餘引用到的對象是否存在)、以及將SQL語句轉換、生成執行計劃等。

 

    Execute:這步是真正的由ORACLE來執行語句。對於insertupdatedelete操做,這步會修改數據,對於select操做,這步就只是肯定選擇的記錄。

    Fetch:返回查詢語句中所得到的記錄,這步只有select語句會被執行。

 

count   這個語句被parseexecutefetch的次數。

cpu     :這個語句對於全部的parseexecutefetch所消耗的cpu的時間,以秒爲單位。

elapsed :這個語句全部消耗在parseexecutefetch的總的時間。

disk    :從磁盤上的數據文件中物理讀取的數據塊的數量。

query   :在一致性讀模式下,一致性讀的數量。

current :在current模式下,即當前模式讀下db blocks gets的數量。

rows    全部SQL語句返回的記錄數目,可是不包括子查詢中返回的記錄數目。對於select語句,返回記錄是在fetch這步,對於insertupdatedelete操做,返回記錄則是在execute這步。 


以下截圖所示(圖1與圖2本是鏈接在一塊兒的,因爲太長,分開截圖,兩張圖片有相同部分),因爲咱們實驗過程當中,並無採集統計信息,你會看到trac文件裏面有一個動態採樣(若是你在建立表,作一次統計信息收集,結果會有一些差異),另外,物理讀和一致性讀以下,跟上面的執行計劃中的數據一致。


disk(物理讀)      = 747+282 = 1029

query(一致性讀)   = 1035+74 = 1109

clip_image003

clip_image004

 

繼續分析格式化的prf文件,咱們會看到第二次查詢的query(一致性讀)爲1034, disk(物理讀)爲0


clip_image005

 

上面例子,讓咱們瞭解了物理讀、一致性讀,那麼接下來看看當前模式讀(db block gets)的例子

SQL> create table t

   

  2  ( id  number(10)

   

  3  );

   

 

   

Table created.

   

 

   

SQL> set autotrace on;

   

SQL> insert into t

   

  2  values(1000);

   

 

   

1 row created.

   

 

   

 

   

Execution Plan

   

----------------------------------------------------------

   

---------------------------------------------------------------------------------

   

| Id  | Operation                | Name | Rows  | Bytes | Cost (%CPU)| Time     |

   

---------------------------------------------------------------------------------

   

|   0 | INSERT STATEMENT         |      |     1 |   100 |     1   (0)| 00:00:01 |

   

|   1 |  LOAD TABLE CONVENTIONAL | T    |       |       |            |          |

   

---------------------------------------------------------------------------------

   

 

   

Statistics

   

----------------------------------------------------------

   

          1  recursive calls

   

          7  db block gets

   

          1  consistent gets

   

          0  physical reads

   

        748  redo size

   

        836  bytes sent via SQL*Net to client

   

        783  bytes received via SQL*Net from client

   

          3  SQL*Net roundtrips to/from client

   

          1  sorts (memory)

   

          0  sorts (disk)

   

          1  rows processed

   

 

   

SQL> insert into t

   

  2  values(1001);

   

 

   

1 row created.

   

 

   

 

   

Execution Plan

   

----------------------------------------------------------

   

---------------------------------------------------------------------------------

   

| Id  | Operation                | Name | Rows  | Bytes | Cost (%CPU)| Time     |

   

---------------------------------------------------------------------------------

   

|   0 | INSERT STATEMENT         |      |     1 |   100 |     1   (0)| 00:00:01 |

   

|   1 |  LOAD TABLE CONVENTIONAL | T    |       |       |            |          |

   

---------------------------------------------------------------------------------

   

 

   

Statistics

   

----------------------------------------------------------

   

          1  recursive calls

   

          1  db block gets

   

          1  consistent gets

   

          0  physical reads

   

        308  redo size

   

        837  bytes sent via SQL*Net to client

   

        783  bytes received via SQL*Net from client

   

          3  SQL*Net roundtrips to/from client

   

          1  sorts (memory)

   

          0  sorts (disk)

   

          1  rows processed

   

 

clip_image006

 

一致性讀如何計算呢?

 

關於一致性讀如何計算呢? 我查了一下資料,通常一致性讀consistent gets ~= numrows/arraysize + blocks ,確切的說是consistent reads計算 ~=ceil(獲取行數(card)/arraysize)+used blocks, 並且這個不是絕對等於,而是約等於的關係。 可是這個不是官方資料,而是asktom和一些技術博客的介紹,咱們來驗證看看吧

 

   

SQL> exec dbms_stats.gather_table_stats(user, 'TEST');

   

 

   

PL/SQL procedure successfully completed.

   

 

   

SQL>

   

SQL> set autotrace traceonly stat

   

SQL> select * from test;

   

 

   

72271 rows selected.

   

 

   

 

   

Statistics

   

----------------------------------------------------------

   

        448  recursive calls

   

          0  db block gets

   

       5846  consistent gets

   

       1031  physical reads

   

          0  redo size

   

    8296071  bytes sent via SQL*Net to client

   

      53521  bytes received via SQL*Net from client

   

       4820  SQL*Net roundtrips to/from client

   

          3  sorts (memory)

   

          0  sorts (disk)

   

      72271  rows processed

   

SQL> /

   

 

   

72271 rows selected.

   

 

   

 

   

Statistics

   

----------------------------------------------------------

   

          0  recursive calls

   

          0  db block gets

   

       5789  consistent gets

   

          0  physical reads

   

          0  redo size

   

    8296071  bytes sent via SQL*Net to client

   

      53521  bytes received via SQL*Net from client

   

       4820  SQL*Net roundtrips to/from client

   

          0  sorts (memory)

   

          0  sorts (disk)

   

      72271  rows processed

   

 

clip_image007

SQL> set autotrace off;

   

SQL> set serveroutput on;

   

SQL> exec show_space('TEST',USER);

   

Free Blocks.............................               0

   

Total Blocks............................           1,152

   

Total Bytes.............................       9,437,184

   

Total MBytes............................               9

   

Unused Blocks...........................             121

   

Unused Bytes............................         991,232

   

Last Used Ext FileId....................               1

   

Last Used Ext BlockId...................          89,344

   

Last Used Block.........................               7

   

 

   

PL/SQL procedure successfully completed.

   

 

   

SQL> show arraysize ;

   

arraysize 15

   

SQL> select ceil(72271/15) + 1152-121 from dual;

   

 

   

CEIL(72271/15)+1152-121

   

-----------------------

   

                   5850

   

 

   

SQL> SELECT COUNT(DISTINCT dbms_rowid.rowid_block_number(ROWID)) AS blocks FROM TEST;

   

 

   

    BLOCKS

   

----------

   

      1030

   

 

   

SQL> SELECT  ceil(72271/15) + 1030 FROM DUAL;

   

 

   

CEIL(72271/15)+1030

   

-------------------

   

               5849

clip_image008

 

不論是5849仍是5850,都和5879 或5846有一點的出入?也就是說上面那個公式不能用等於號,關於這個,其實在https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:880343948514 裏面,你會看到這裏介紹的也是一個約等於關係,而不是一個絕對等於的關係。在這裏我想深刻一點,無奈知識有限。 從上面的公式, 咱們能夠看到一致性讀跟arraysize的關係是蠻大的。那麼咱們來測試驗證一下,先將araraysize調整爲50

SQL> set autotrace off;

   

SQL> set arraysize 50

   

SQL> set autotrace traceonly stat;

   

SQL> select * from test;

   

 

   

72271 rows selected.

   

 

   

 

   

Statistics

   

----------------------------------------------------------

   

          0  recursive calls

   

          0  db block gets

   

       2456  consistent gets

   

          0  physical reads

   

          0  redo size

   

    7668743  bytes sent via SQL*Net to client

   

      16418  bytes received via SQL*Net from client

   

       1447  SQL*Net roundtrips to/from client

   

          0  sorts (memory)

   

          0  sorts (disk)

   

      72271  rows processed

   

 

   

SQL>

clip_image009

SQL> SELECT  ceil(72271/50) + 1030 FROM DUAL;

   

 

   

CEIL(72271/50)+1030

   

-------------------

   

               2476

   

 

   

SQL>

 

如上所示,一致性讀從5789降爲了2456,有興趣的能夠作一下實驗。另外,因爲在Oracle中,取數據最後都是從buffer cache中取,因此每出現一個physical reads必然會出現一次 logical reads. 也就是說物理讀(physical reads)必定小於邏輯讀(logical reads=db block gets + consistent gets),也就是說物理讀必定小於一致性讀,可是也有物理讀大於邏輯讀的狀況,具體參考官方文檔 Why Physical Read is greater than Logical Read in Tkprof (文檔 ID 211700.1)

PURPOSE

In some circumstances, you can find that tkprof report shows more physical reads than logical reads, which isn't the current result as the physical reads are normally included in logical reads.

SCOPE & APPLICATION

This article will be useful for the DBA's and customers who are concerned by the tuning of Requests.

Why Physical reads are greater than Logical reads

Sometimes, you can find the following content in tkprof report:

· Physical Reads = Disk (total)

· Logical Reads = Query (total) + Current (total)

call

count

cpu

elapsed

disk

query

current

rows

-------

------

--------

----------

----------

----------

----------

----------

Parse

1

0.67

1.10

0

0

0

0

Execute

1

0.00

0.00

0

0

0

0

Fetch

2202

167.48

678.70

579441

283473

17418

33014

-------

------

--------

----------

----------

----------

----------

----------

total

2204

168.15

679.81

579441

283473

17418

33014

The 'disk' column is then greater than the 'query' + 'current' columns. This isn't usual.

To find the root cause of the problem, you must generate a 10046 event trace file level 8 and check for direct read waits in it.

In 10046 raw trace, you will find "direct path read" and "direct path write" waits like the example below:

WAIT #1: nam='direct path read' ela= 10076 p1=4 p2=29035 p3=1

with P1 = file#P2 = start block#P3 = num blocks

The "direct path read" waits account explains the difference between logical and physical reads.

In Oracle 9.2 and above, TKProf will print waits associated with each SQL statement in the output file.

Explanation:

The reason for more physical reads than logical reads is due to the number of direct reads block access. Direct path reads are generally used by Oracle when reading directly into PGA memory (as opposed to into the buffer cache).

They may happen on different actions:

· Sort IO on disk.

· Read by parallel Query Slaves when scanning is done.

· Blocks read by anticipation (readahead).

Such reads are done without loading blocks into the Buffer Cache. They can be single or multiblock reads.

Utilizing Direct Path Reads in this manner prevents the Oracle Buffer cache from beeing overloaded.

Oracle uses this optimisation when it considers that its not necessary to share the blocks between different sessions.

 

最後咱們來看一個,熱表上一致性讀飆漲的案例,其實這個是Oracle 9i&10g編程藝術:深刻數據庫體系結構這本書籍裏面的一個案例,咱們在此重演一遍,但願能加深你們對一致性讀的理解,首先準備測試數據環境

SQL> show user;

   

USER is "TEST"

   

SQL> create table t( x int);

   

 

   

Table created.

   

 

   

SQL> insert into t values(1);

   

 

   

1 row created.

   

 

   

SQL> commit;

   

 

   

Commit complete.

   

 

   

SQL> exec dbms_stats.gather_table_stats(user, 'T');

   

 

   

PL/SQL procedure successfully completed.

   

 

   

 

   

SQL> set autotrace on statistics;

   

SQL> select * from t;

   

 

   

         X

   

----------

   

         1

   

 

   

 

   

Statistics

   

----------------------------------------------------------

   

          0  recursive calls

   

          0  db block gets

   

          7  consistent gets

   

          0  physical reads

   

          0  redo size

   

        523  bytes sent via SQL*Net to client

   

        523  bytes received via SQL*Net from client

   

          2  SQL*Net roundtrips to/from client

   

          0  sorts (memory)

   

          0  sorts (disk)

   

          1  rows processed

   

 

   

SQL>

clip_image010

 

如上所示,通常狀況下一致性讀爲7,可是咱們在一個會話窗口準備執行下面SQL,頻繁修改表T

 

   

SQL> begin

   

  2   for i in 1 .. 100000

   

  3   loop

   

  4     update t set x=x+1;

   

  5     commit;

   

  6   end loop;

   

  7  end;

   

  8  /

   

 

   

PL/SQL procedure successfully completed.

 

在上面會話執行的同時,咱們在另一個會話窗口立刻執行下面SQL,你會看到一致性讀飆漲。

SQL> alter session set isolation_level=serializable;

   

 

   

Session altered.

   

 

   

SQL> set autotrace on statistics;

   

SQL> select * from t;

   

 

   

         X

   

----------

   

         1

   

 

   

 

   

Statistics

   

----------------------------------------------------------

   

          1  recursive calls

   

          0  db block gets

   

      23681  consistent gets

   

          0  physical reads

   

          0  redo size

   

        523  bytes sent via SQL*Net to client

   

        523  bytes received via SQL*Net from client

   

          2  SQL*Net roundtrips to/from client

   

          0  sorts (memory)

   

          0  sorts (disk)

   

          1  rows processed

clip_image011

 

將會話設置爲使用SERIALIZABLE 隔離級別,這樣不管在會話中運行多少次查詢,都將獲得事務開始時刻的查詢結果。具體分析不在此多此一舉,你們感興趣的能夠去看看Oracle9i&10g編程藝術:深刻數據庫體系結構。

 

參考資料:

https://docs.oracle.com/cd/B19306_01/server.102/b14220/consist.htm#i13945

https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:880343948514

Oracle 9i&10g編程藝術:深刻數據庫體系結構

做者:瀟湘隱者  

出處:http://www.cnblogs.com/kerrycode/  





  在sql調優的時候,一個關鍵指標就是consistent gets,若是這個指標很低,通常認爲sql語句執行仍是很高效的,反之效率會很低。可是這個指標咱們知之甚少,對於這個指標的計算方式咱們也是懵懵懂懂。對於邏輯讀來講,通常都是基於Logical Reads= Consistent Gets + DB Block Gets  
若是咱們知道logical reads是1000,咱們可能錯誤地認爲查詢讀取了1000*8k(約爲8M)  
看了博客https://viveklsharma.wordpress.com/2010/03/04/consistent-gets-myth/後,發現本身的認識是錯誤的,也按捺不住在本地測試了一把,受益不淺。  
首先咱們來建立一個表,數據量爲2000條。  
n1@TEST11G> create table test_consistent_get  as select * from all_objects where rownum between 1 and 2000;  
Table created.  
而後收集統計信息  
n1@TEST11G> exec dbms_stats.gather_table_stats(user,'TEST_CONSISTENT_GET');                                 
PL/SQL procedure successfully completed.  
查看相應的數據塊爲30個  
n1@TEST11G> select num_rows,blocks,table_name,last_analyzed,global_stats from user_tables where table_name='TEST_CONSISTENT_GET';     
  NUM_ROWS     BLOCKS TABLE_NAME                     LAST_ANAL GLO  
---------- ---------- ------------------------------ --------- ---  
      2000         30 TEST_CONSISTENT_GET            20-APR-15 YES  
n1@TEST11G> set autot trace  
咱們來看看執行計劃,很明顯走了一個全表掃描。可是咱們須要關注的是統計信息中的consistent gets  
n1@TEST11G> select * from test_consistent_get;                                                                                                                                           
Execution Plan  
----------------------------------------------------------  
Plan hash value: 1444268095  
-----------------------------------------------------------------------------------------  
| Id  | Operation         | Name                | Rows  | Bytes | Cost (%CPU)| Time     |  
-----------------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT  |                     |  2000 |   164K|    10   (0)| 00:00:01 |  
|   1 |  TABLE ACCESS FULL| TEST_CONSISTENT_GET |  2000 |   164K|    10   (0)| 00:00:01 |  
-----------------------------------------------------------------------------------------  
Statistics  
----------------------------------------------------------  
          1  recursive calls  
          0  db block gets  
        163  consistent gets  
          0  physical reads  
          0  redo size  
     199754  bytes sent via SQL*Net to client  
       1883  bytes received via SQL*Net from client  
        135  SQL*Net roundtrips to/from client  
          0  sorts (memory)  
          0  sorts (disk)  
       2000  rows processed         
能夠看到這個表佔用的數據塊爲30,可是consistent gets卻爲163,很顯然不是說這個全表掃描向cache裏讀入了163*8k的數據  
咱們能夠經過rowid來獲得對應的數據塊和其中的數據狀況  
n1@TEST11G> select dbms_rowid.ROWID_BLOCK_NUMBER(rowid) blkno, count(*) cnt  
    from test_consistent_get  
    group by dbms_rowid.ROWID_BLOCK_NUMBER(rowid) order by 1;  
     BLKNO        CNT  
---------- ----------  
    263827         88  
    263828         84  
    263829         81  
    263830         76  
    263831         81  
    263832         80  
    263833         82  
    263834         77  
    263835         73  
    263836         78  
    263837         79  
    263838         79  
    263839         81  
    263841         82  
    263842         77  
    263843         81  
    263844         80  
    263845         81  
    263846         78  
    263847         78  
    263848         76  
    263849         78  
    263850         78  
    263851         76  
    263852         81  
    263853         15  
26 rows selected.  
能夠經過rowid獲得相關的數據塊爲26個。查看段頭,發現對應的數據塊是263826是不在上面的rowid對應的數據塊範圍內的。  
n1@TEST11G> select header_block,blocks ,extents from dba_segments where segment_name='TEST_CONSISTENT_GET';  
HEADER_BLOCK     BLOCKS    EXTENTS  
------------ ---------- ----------  
      263826         32          4  
對應的區和數據塊信息以下:  
n1@TEST11G> select EXTENT_ID, FILE_ID, BLOCK_ID, BLOCKS from dba_extents where SEGMENT_NAME='TEST_CONSISTENT_GET';  
 EXTENT_ID    FILE_ID   BLOCK_ID     BLOCKS  
---------- ---------- ---------- ----------  
         0          4     263824          8  
         1          4     263832          8  
         2          4     263840          8  
         3          4     263848          8  
下面的語句能夠算出對於每一個數據塊對應的consistent gets的值。  
n1@TEST11G>   
variable b1 number;  
exec :b1:=15;  
 compute sum of total_cnt on report  
 compute sum of touch_cnt on report  
 break on report  
select blkno, total_cnt, final_cnt, rows_remaining,  
case when rows_remaining=0 then touch_cnt+1 else touch_cnt end touch_cnt  
from (  
select blkno, total_cnt, final_cnt, rows_remaining,  
case when total_cnt = final_cnt then ceil(final_cnt/:b1) else ceil(final_cnt/:b1)+1 end touch_cnt  
from (  
select blkno, cnt total_cnt,   
case when rownum=1 or lag(rows_remaining) over (order by blkno)=0   
                     then cnt else (cnt-(:b1-lag(rows_remaining) over (order by blkno))) end final_cnt,  
rows_remaining   
from (  
select blkno, cnt, rr,   
lead(rr) over(order by blkno) next_rr,  
lead(blkno) over(order by blkno) next_blk,  
ceil(rr/:b1) touch_cnt,  
mod(rr,:b1) rows_remaining  
from (  
select dbms_rowid.ROWID_BLOCK_NUMBER(rowid) blkno, count(*) cnt,   
sum(count(*)) over(order by dbms_rowid.ROWID_BLOCK_NUMBER(rowid)) rr   
from test_consistent_get  
group by dbms_rowid.ROWID_BLOCK_NUMBER(rowid) order by 1))));  

     BLKNO  TOTAL_CNT  FINAL_CNT ROWS_REMAINING  TOUCH_CNT  
---------- ---------- ---------- -------------- ----------  
    263827         88         88             13          6  
    263828         84         82              7          7  
    263829         81         73             13          6  
    263830         76         74             14          6  
    263831         81         80              5          7  
    263832         80         70             10          6  
    263833         82         77              2          7  
    263834         77         64              4          6  
    263835         73         62              2          6  
    263836         78         65              5          6  
    263837         79         69              9          6  
    263838         79         73             13          6  
    263839         81         79              4          7  
    263841         82         71             11          6  
    263842         77         73             13          6  
    263843         81         79              4          7  
    263844         80         69              9          6  
    263845         81         75              0          7  
    263846         78         78              3          6  
    263847         78         66              6          6  
    263848         76         67              7          6  
    263849         78         70             10          6  
    263850         78         73             13          6  
    263851         76         74             14          6  
    263852         81         80              5          7  
    263853         15          5              5          2  
           ----------                           ----------  
sum              2000                                  159  
能夠看到對於這個全表掃描的場景,consistent gets不是衡量對於cache的數據塊數而是次數。  
好比對於上面的數據塊   263827 ,數據條數爲88條,arraysize爲15,則能夠簡單說明一下是如何計算這個consistent gets值的。
對於數據塊263827,放入PGA中,獲得了15行,這個時候能夠理解爲consistent gets=1
對於數據塊263827,再次從PGA中獲得,獲得了15行,這個時候consistent gets=2
依次類推
對於數據塊263827,再次從PGA中獲得,獲得了13行,這個時候consistent gets=6
或者也能夠基本按照這個公式來計算,數據行數/arraysize+數據塊數=consistent gets
好比這個例子,2000/15+30 大概是163.3左右,因此163仍是靠譜的。
對於arraysize未20,30,的狀況下,相應的consistent gets也會減小。簡單模擬一下。
 
n1@TEST11G> set arraysize 20    
n1@TEST11G> set autot trace exp stat  
n1@TEST11G> select *from test_consistent_get;  
Statistics  
----------------------------------------------------------  
          1  recursive calls  
          0  db block gets  
        128  consistent gets  
          0  physical reads  
          0  redo size  
     195334  bytes sent via SQL*Net to client  
       1509  bytes received via SQL*Net from client  
        101  SQL*Net roundtrips to/from client  
          0  sorts (memory)  
          0  sorts (disk)  
       2000  rows processed  
n1@TEST11G> set autot off  
n1@TEST11G> select 2000/20+30 from dual;  
2000/20+30  
----------  
       130  
n1@TEST11G> set arraysize 30  
n1@TEST11G> set autot trace  stat  
n1@TEST11G> select *from test_consistent_get;  
Statistics  
----------------------------------------------------------  
          0  recursive calls  
          0  db block gets  
         96  consistent gets  
          0  physical reads  
          0  redo size  
     191044  bytes sent via SQL*Net to client  
       1146  bytes received via SQL*Net from client  
         68  SQL*Net roundtrips to/from client  
          0  sorts (memory)  
          0  sorts (disk)  
       2000  rows processed  
n1@TEST11G> set autot off           
n1@TEST11G> select 2000/30+30 from dual;  
2000/30+30  
----------  
96.6666667    

相關文章
相關標籤/搜索