在ORACLE資料庫中有實體讀(Physical Reads)、邏輯讀(Logical Reads)、一緻性讀(Consistant Get)、目前模式讀(DB Block Gets)等諸多概念,如果不了解或混淆這些概念的話,對你深入了解一些知識無疑是一個障礙,但是這些概念确實挺讓讓人犯暈的。下面我們總結、學習一下這方面的知識點。捋一捋他們的關系和特點,希望對你有所幫助。
<b>實體讀(Physical Reads) </b>
從磁盤讀取資料塊到記憶體的操作叫實體讀,當SGA裡的高速緩存(Cache Buffer)裡面不存在這些資料塊時,就會産生實體讀,另外。像全表掃描、磁盤排序等操作也可能産生實體讀,原因也是因為ORACLE資料庫需要通路的資料塊較多,而有些資料塊不在記憶體當中,需要從磁盤讀取。
<b>邏輯讀(Logical Reads)</b>
概念1:邏輯讀指ORACLE從記憶體讀到的資料塊數量。一般來說, logical reads = db block gets + consistent gets
概念2:邏輯讀指的就是從Buffer Cache中讀取資料塊。按照通路資料塊的模式不同,可以分為目前模式讀(Current Read)和一緻性讀(Consistent Read)。
這兩個概念本質是一樣的,隻是措辭不一樣。
<b>一緻性讀(Consistant Get)</b>
ORACLE是一個多使用者系統。當一個會話開始讀取資料還未結束讀取之前,可能會有其他會話修改了它将要讀取的資料。如果會話讀取到修改後的資料,就會造成資料的不一緻。一緻性讀就是為了保證資料的一緻性。在Buffer Cache中的資料塊上都會有最後一次修改資料塊時的SCN。如果一個事務需要修改資料塊中資料,會先在復原段中儲存一份修改前資料和SCN的資料塊,然後再更新Buffer Cache中的資料塊的資料及其SCN,并辨別其為“髒”資料。當其他程序讀取資料塊時,會先比較資料塊上的SCN和程序自己的SCN。如果資料塊上的SCN小于等于程序本身的SCN,則直接讀取資料塊上的資料;如果資料塊上的SCN大于程序本身的SCN,則會從復原段中找出修改前的資料塊讀取資料。通常,普通查詢都是一緻性讀。
<b>目前模式讀(DB Block Gets)</b>
<b></b>
個人覺得目前模式讀(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。
了解完了概念,如果你還是有一些疑問和不解,那我們結合實際例子來了解一下這些概念吧。如下所示:
<a href="http://images2015.cnblogs.com/blog/73542/201610/73542-20161008234000223-1369387845.png"></a>
如上截圖所示, SQL語句第一次執行時,一緻性讀(consistent gets)為1109, 實體讀(physical reads)為1029,目前模式讀(db block gets)為0. 如果你再執行一次上面SQL語句,你會發現實體讀(physical reads)會降低為0了,因為上一次查詢,ORACLE已經将表test的所有資料塊讀取到buffer cache裡面了。當然生産環境實際情況會複雜很多。
<a href="http://images2015.cnblogs.com/blog/73542/201610/73542-20161008234001848-1967127953.png"></a>
我們先用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來執行語句。對于insert、update、delete操作,這步會修改資料,對于select操作,這步就隻是确定選擇的記錄。
Fetch:傳回查詢語句中所獲得的記錄,這步隻有select語句會被執行。
count : 這個語句被parse、execute、fetch的次數。
cpu :這個語句對于所有的parse、execute、fetch所消耗的cpu的時間,以秒為機關。
elapsed :這個語句所有消耗在parse、execute、fetch的總的時間。
disk :從磁盤上的資料檔案中實體讀取的資料塊的數量。
query :在一緻性讀模式下,一緻性讀的數量。
current :在current模式下,即目前模式讀下db blocks gets的數量。
rows : 所有SQL語句傳回的記錄數目,但是不包括子查詢中傳回的記錄數目。對于select語句,傳回記錄是在fetch這步,對于insert、update、delete操作,傳回記錄則是在execute這步。
如下截圖所示(圖1與圖2本是連接配接在一起的,由于太長,分開截圖,兩張圖檔有相同部分),由于我們實驗過程中,并沒有采集統計資訊,你會看到trac檔案裡面有一個動态采樣(如果你在建立表,做一次統計資訊收集,結果會有一些差别),另外,實體讀和一緻性讀如下,跟上面的執行計劃中的資料一緻。
<b>disk(</b><b>實體讀) = 747+282 = 1029 </b>
<b>query(</b><b>一緻性讀) = 1035+74 = 1109 </b>
<a href="http://images2015.cnblogs.com/blog/73542/201610/73542-20161008234002957-751363062.png"></a>
<a href="http://images2015.cnblogs.com/blog/73542/201610/73542-20161008234004364-1325863870.png"></a>
繼續分析格式化的prf檔案,我們會看到第二次查詢的query(一緻性讀)為1034, disk(實體讀)為0
<a href="http://images2015.cnblogs.com/blog/73542/201610/73542-20161008234006457-1575624894.png"></a>
上面例子,讓我們了解了實體讀、一緻性讀,那麼接下來看看目前模式讀(db block gets)的例子
<a href="http://images2015.cnblogs.com/blog/73542/201610/73542-20161008234007426-1145645612.png"></a>
<b></b>
<b>一緻性讀如何計算呢?</b>
關于一緻性讀如何計算呢? 我查了一下資料,一般一緻性讀consistent gets ~= numrows/arraysize + blocks ,确切的說是consistent reads計算 ~=ceil(擷取行數(card)/arraysize)+used blocks, 而且這個不是絕對等于,而是約等于的關系。 但是這個不是官方資料,而是asktom和一些技術部落格的介紹,我們來驗證看看吧
<a href="http://images2015.cnblogs.com/blog/73542/201610/73542-20161008234008489-1882172711.png"></a>
<a href="http://images2015.cnblogs.com/blog/73542/201610/73542-20161008234009973-1269630737.png"></a>
不管是5849還是5850,都和5879 或5846有一點的出入?也就是說上面那個公式不能用等于号,關于這個,其實在https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:880343948514 裡面,你會看到這裡介紹的也是一個約等于關系,而不是一個絕對等于的關系。在這裡我想深入一點,無奈知識有限。 從上面的公式, 我們可以看到一緻性讀跟arraysize的關系是蠻大的。那麼我們來測試驗證一下,先将araraysize調整為50
<a href="http://images2015.cnblogs.com/blog/73542/201610/73542-20161008234010754-2049077509.png"></a>
如上所示,一緻性讀從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)
<b>PURPOSE</b><b> </b>
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.
<b>SCOPE & APPLICATION</b>
This article will be useful for the DBA's and customers who are concerned by the tuning of Requests.
<b>Why Physical reads are greater than Logical reads</b>
Sometimes, you can find the following content in tkprof report:
· <b>Physical Reads = Disk (total)</b>
· <b>Logical Reads = Query (total) + Current (total)</b>
call
count
cpu
elapsed
disk
query
current
rows
-------
------
--------
----------
Parse
1
0.67
1.10
Execute
0.00
Fetch
2202
167.48
678.70
579441
283473
17418
33014
total
2204
168.15
679.81
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 "<b>direct path read</b>" and "<b>direct path write</b>" waits like the example below:
<b>WAIT #1: nam='direct path read' ela= 10076 p1=4 p2=29035 p3=1 </b>
with <b>P1 = file#</b>, <b>P2 = start block#</b>, <b>P3 = num blocks</b>
The "<b>direct path read</b>" 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.
<b>Explanation:</b>
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).
<b>They may happen on different actions:</b>
· <b>Sort IO on disk.</b>
· <b>Read by parallel Query Slaves when scanning is done.</b>
· <b>Blocks read by anticipation (readahead).</b>
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.
最後我們來看一個,熱表上一緻性讀飙漲的案例,其實這個是<b>Oracle</b><b> </b><b>9i&10g</b><b>程式設計藝術:深入資料庫體系結構</b>這本書籍裡面的一個案例,我們在此重演一遍,希望能加深大家對一緻性讀的了解,首先準備測試資料環境
<a href="http://images2015.cnblogs.com/blog/73542/201610/73542-20161008234011739-270224987.png"></a>
如上所示,一般情況下一緻性讀為7,但是我們在一個會話視窗準備執行下面SQL,頻繁修改表T
在上面會話執行的同時,我們在另外一個會話視窗馬上執行下面SQL,你會看到一緻性讀飙漲。
<a href="http://images2015.cnblogs.com/blog/73542/201610/73542-20161008234012660-1658232673.png"></a>
将會話設定為使用SERIALIZABLE 隔離級别,這樣無論在會話中運作多少次查詢,都将得到事務開始時刻的查詢結果。具體分析不在此畫蛇添足,大家感興趣的可以去看看<b>Oracle</b><b> </b><b>9i&10g</b><b>程式設計藝術:深入資料庫體系結構。</b>
<b>參考資料:</b>
<a href="https://docs.oracle.com/cd/B19306_01/server.102/b14220/consist.htm#i13945">https://docs.oracle.com/cd/B19306_01/server.102/b14220/consist.htm#i13945</a>
<a href="https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:880343948514">https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:880343948514</a>
<b>Oracle</b><b> </b><b>9i&10g</b><b>程式設計藝術:深入資料庫體系結構</b>