oracle學習筆記 SQL語句執行過程剖析講課

oracle學習筆記

SQL語句執行過程剖析講課

這節課通過講述一條SQL語句進入數據庫
和其在數據庫中的整個的執行過程
把數據庫裏面的體系結構串一下。
讓大家再進一步瞭解oracle數據庫裏面的各個進程、存儲結構以及內存結構的關聯關係。

首先來講整個體系中有客戶端、實例和數據庫

數據庫裏有三類文件
控制文件ctl、數據文件dbf、日誌文件log

實例中SGA有六大池子
第一大內存區shared pool即共享池
第二大內存區buffer cache
第三塊是redo log
我們主要講上面的三大池它們容易出問題,
特別是shared pool和buffer cache。
另外三大池不會出問題。
接下來的幾個章節主要講shared pool ,buffer cache。

一)shared pool
用戶連接上實例,
實例會專門針對這個連接開一個進程,
這個進程叫前臺進程也叫服務器進程,翻譯成英文叫server process。
它是實例的進程,
oracle會單獨的給它分配一個PGA空間。

在客戶端錄入一條sql,
輸入後回車,
如:
SQL> select * from dba_data_files;
執行後獲得一堆數據。

這條語句在客戶端輸入,
然後通過客戶端到實例的鏈接送給了server process。
在服務端,
sql語句通過網絡送給oracle,被oracle的server process接受和接待。

server process接受到這個sql語句
然後做的事情

1、這條語句oracle認識,但不能直接運行
oracle需要將sql語句解析成執行計劃然後才能執行。

2、解析後oracle拿着執行計劃去執行。

解析的過程應該說是比較複雜的,
包括很多步驟
server process首先會判斷sql語句語法有沒有問題,如果有問題不會執行後面的操作。
還看一下,sql語句所涉及的表、視圖在數據庫裏到底有沒有。
接下來看一下輸入sql語句的用戶對sql語句所涉及的表和視圖有沒有權限。
還有一個重要的工作,
判斷sql語句到底該怎麼執行。
一條sql語句可以有N種執行方案,
這n中執行方案中有的執行方案是好的,有的是不好的。
這時候serverprocess要從這條sql語句的n個執行方案中找一個最優的執行方案。
然後生成執行計劃。

在選擇最優執行方案的過程中,它要訪問很多對象,訪問很多數據,
否則它不能憑空的判斷哪個方案最優秀。
這時需要消耗很多的計算機資源
最主要消耗cpu資源,其次是IO資源,再者是內存資源。

既然解析會消耗資源,這時候會想到另外一個問題

A用戶執行一條sql語句
這條sql語句需要解析,解析完生成執行計劃。
A用戶執行了。

B用戶連上以後和A用戶做相同的業務,
比如兩個營業員都做的是取款,業務相同。
有可能執行相同的sql語句。

A用戶執行時生成的執行計劃,如果能夠緩存起來的話,
B用戶上來後,如果能夠找到這個緩存的執行計劃,
它就不需要經過解析了,可以直接拿着執行計劃去執行。

在數據庫裏面就提到一個問題,
我們有沒有必要對sql語句和sql語句所對應的執行計劃進行緩存?
現在看有必要。
sql語句和sql語句所對應的執行計劃我們緩存在shared pool中。

回顧一下:
一條sql語句在客戶端輸入,
通過網絡到達oracle實例,
實例中server process來接收這條語句,
server process接收到後會拿着sql語句
首先進到shared pool裏面,
要看一下這條sql語句在shared pool中有沒有緩存。
如果有緩存,
這時server process會在shared pool中找到這條sql語句以及所對應的執行計劃,
然後再去執行。
減少了解析的步驟。
如果server process在sharedpool中沒有找到這條sql語句以及對應的執行計劃,
這時server process 就會將sql進行解析,最終生成執行計劃。
然後接着下一步去執行。

server process拿到sql語句要執行的第一件事情是:
找,
如果找不找它會去解析。
這兩個過程都是server process所做的。

shared pool最主要的一個事情就是緩存sql語句和sql語句所對應的執行計劃。

對shared pool的訪問以及對sharedpool的修改這些操作都是serverprocess進程進行的。

二)buffer cache
SQL語句解析完,生成執行計劃,接着要執行。
sql語句執行時,要去取數據
如語句:
select * from dba_data_files
要從dba_data_files表中取數據。

表的數據都在磁盤dbf文件裏面,
這時還是server process要根據這個sql語句的執行計劃去執行。
這個sql語句的執行計劃從dbf裏面取出數據,然後返給用戶。

buffer cache 就是用來緩存dbf的數據。

非常有必要緩存。
因爲A用戶訪問了某個表,B用戶訪問這個表的可能性也比較大。
A用戶再來訪問這個表的機會也比較大。
如果沒有buffer cache的話,
每次訪問dbf時,都要發生物理IO,數據庫的性能會非常低。

當一個進程訪問dbf訪問我們的數據的時候,
如要訪問一個表的數據,
因爲server process知道有緩存buffer cache這個概念,
首先到buffer cache裏面找這個表所對應的數據在buffer cache裏面有沒有。
如果有,server process直接訪問buffer cache,
把所有的數據取出來,通過網絡再返給客戶端。
如果buffercache中沒有它要找的數據,這個時候它就到磁盤dbf去找。
從dbf中把數據取出來,取出來不是直接返回給我們的用戶,
取出來以後放到buffer cache裏面去,
然後再從buffercache中返給我們的用戶。

對oracle來講,從dbf裏面取數據,取到buffercache裏面,爲物理讀,
這個操作是serverprocess來完成的。

講兩個概念:
邏輯IO
logic IO
物理IO
Physical IO

邏輯IO,
serverprocess執行sql語句的時候
從buffercache裏面讀,叫邏輯讀,也叫內存讀。
物理IO,
buffercache中找不到數據,
它就到磁盤上去讀,這個讀叫物理讀,也叫磁盤讀。

我們希望邏輯讀多一些,物理讀少一些。
這樣會大大減少物理讀的數量,進而提高數據庫的訪問速度。

命中率的概念
命中率在緩存裏面時刻被提出來,
在buffercache裏面有命中率,計算方法L/L+P,就是:邏輯讀/邏輯讀+物理讀
命中率越高,說明邏輯讀相對比較大,物理讀相對比較小。

這是相對。
我們希望命中率高相對好一些。
命中率高意味着物理讀少,邏輯讀相對多一些。
物理讀高IO就會很繁忙,數據庫的速度就會比較慢。

比如:
oracle發生100次讀,其中只有一次物理讀99次邏輯讀。
算法 99/99+1
命中率爲99%。

這個時候我們就說,buffercache的命中率爲99%。
oracle讀數據100次 只有一次物理讀,99次邏輯讀。
大幅的提高了數據庫的讀的性能。這是好事。

對oracle數據庫來講,
命中率低肯定有問題。
命中率高不一定沒有問題。

舉例:
邏輯讀10萬,物理讀1萬
在一個時間段裏面物理讀也挺高。

計算命中率的時候我們發現,
因爲邏輯讀非常的大,命中率也很高,
但是數據庫整體的服務速度也很慢。

所以說命中率低肯定有問題,命中率高不一定沒有問題
有可能是因爲邏輯讀非常高,即使是物理讀比較高,計算命中率也會很大。
命中率大我們就認爲沒問題,但不見得,我們要關心每秒的物理讀。

其實有linux命令可以監控系統設備性能
1、vmstat 
vmstat是一個很全面的性能分析工具,
可以觀察到系統的進程狀態、內存使用、虛擬內存使用、磁盤的IO、
系統(中斷、上下文切換)、CPU使用等
[oracle@redhat4 ~]$ vmstat
procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in    cs us sy id wa
 3  0    204  61596  39456 669880    0    0    13    35  303   174 48 22 30  0

2、iostat
iostat主要用於監控系統設備的IO負載情況,運行時顯示系統的各項統計信息
[oracle@redhat4 ~]$ iostat
Linux 2.6.9-78.ELsmp (redhat4)  2016年07月14日


avg-cpu:  %user   %nice    %sys %iowait   %idle
          47.79    0.05   22.11    0.43   29.61


Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
sda               6.37        51.81       142.53    3267484    8989120
sda1              6.17        51.01       137.64    3216970    8680600
sda2              0.18         0.44         3.86      27814     243424
sda3              0.02         0.34         1.03      21716      65096

從這些數據可以知道 服務器整體是否繁忙。

不僅看命中率反饋問題,還要看物理讀量的問題。

serverprocess在執行sql語句的時候,
需要從磁盤上dbf讀數據的時候,
這個數據serverprocess從dbf裏面讀,
然後讀到buffercache,然後從buffercache再返給用戶。


三)DBWn LGWR進程
sql語句目前是對某個表進行讀,
也有可能對某個表進行修改,進行刪除,
sql分增刪改查

我們以改爲例,假設我們要修改某個表的數據

serverprocess還跟以前一樣,把這個表讀到內存裏面去。
修改也要讀到內存裏面去,
serverprocess在內存裏面對錶進行修改。

修改的時候,oracle數據庫對dbf數據庫所有的修改都會產生日誌。
日誌也是serverprocess產生的。

產生日誌以後會寫到redologbuffer裏面去。

修改完了要提交,
因爲修改的是內存裏面的數據,
內存的數據和dbf裏面的數據就不一樣了,
不一樣就需要寫回dbf,
是誰負責數據從內存寫到硬盤,
不是serverporcess,是另外一個進程,叫dbwrite即DBWn進程
這個進程負責把serverprocess修改的數據寫回磁盤,

是誰負責將redlog buffer裏面的日誌 寫到redlog日誌文件裏面去
也不是serverprocess,是logwrite即LGWR進程

DBWn和LGWR都叫後臺進程,
serverprocess叫前臺進程。

serverprocess只是負責讀出來數據在內存buffercache裏面修改,
然後產生日誌寫到redologbuffer裏面去,
它只負責這些事情。

它不負責把修改後的數據,寫回磁盤,把日誌寫回磁盤,
由DBWn,LGWR負責。

爲什麼serverporcess只負責讀不負責寫入磁盤呢,
這其實是oralce設計的時候一個技巧所在。

serverprocess是直接爲用戶服務的,
用戶把sql語句給了serverprocess,
serverprocess做幾件事情,
對sql語句進行解析,然後執行,然後獲取數據,獲取數據後把結果返給用戶。
serverprocess始終在和用戶打交道,
如果serverprocess慢了,這時候用戶會感到數據庫慢。

我們就希望讓serverprocess去做最有意義的工作,
對一些serverprocess可以不做的事情,交給別人去做。
這樣用戶會得到最好的用戶體驗。

serverprocess負責把數據讀出來。
然後修改完了,把修改完的結果返給用戶。
它對修改的結果,什麼時候寫回磁盤,它不去管,讓DBWn去做。
因爲什麼時候寫回磁盤,用戶不關心,
用戶只關心,我修改某個數據,然後告訴我數據修改好了,它只關心這個問題。
用戶所關心的就是serverprocess所關心的。

所以我們把一些後臺能夠做的事情,
儘量的不給serverprocess去做,
讓後臺進程專門去做。
所以oracle數據庫裏面就有了後臺進程的概念。
後臺進程的特點是用戶不知道,它在後面悄悄的做,
用戶只關心我輸入一個sql語句然後快速的得到結果。

serverprocess不關心一些寫磁盤操作,
是後臺進程去做。
所以產生了DBWn、LGWR這些進程。
所以有前臺和後臺進程。

我們在數據庫優化,和數據庫性能監控的時候,
我們主要關心的是serverprocess。
我們並不過多的關心DBWn和LGWR這些。

serverprocess的快慢直接反饋到數據庫的快慢。
直接反饋到用戶對數據庫的一個感受。

不管後臺進程有多忙,只要serverprocess快速輕鬆
用戶就會感到快速輕鬆。
用戶就會感到數據庫很快。
可能這時後臺進程非常的繁忙,這是我們理想的一個結果。

後臺進程很輕鬆,但是serverprocess很忙
用戶感到數據庫很慢,
你發現數據庫的cpu佔用率不高。
這是一個比較不好的結果。

在oracle數據庫裏面我們非常關心的一個進程是serverprocess。

以後優化的時候,我們經常去看那個serverprocess目前很忙。
哪個serverprocess目前很慢。
這是我們的一個下手點。

四)CKPT進程、SMON、PMON
還有一個檢查點進程,也是oracle的一個進程。
五大後臺進程之一。

這個進程是週期性運行的,
DBWn和LGWR也是週期運行,但頻率比較高,負載相對比較大,都比較忙。
特別是DBWn很忙。

但是CKPT(檢查點進程)這個進程它比較輕鬆,
只是週期性運行,
把數據庫當前的一些狀態信息寫到控制文件和數據文件的頭部。

每個數據文件的頭部都記錄着一些這個數據文件的狀態信息。
checkpoint這個進程,它負責更新控制文件和數據文件的頭部。

它的負載是比較輕的。
幾乎沒有什麼事可幹。

還有兩個進程
SMON(系統監視器)
這個進程是對數據庫實例進行維護的
舉一個例子
共享池裏面放的sql語句和執行計劃
用的時間長了,裏面可能出現很多碎片。
這時SMonitor會對這些碎片進行整合。

也就是說SMonitor負責對數據庫實例內部進行清理和維護的。
它主內。

PMON(進程監視器)
它主外
主內是指對SGA內部進行一些維護。
主外是對serverprocess進行維護。
例子
客戶網絡突然斷了,serverprocess還一直爲用戶啓着。
PMonitor會週期性的啓動,
啓動後發現某個serverprocess它所對應的客戶已經死掉了,
他會把這個serverprocess進行清理。
包括把這個serverprocess進程關掉,
把這個serverprocess所對應的PGA內存空間,給它清理。

PMonitor主外 SMonitor主內

現在講了五大進程。

五)ARCn進程
數據庫文件還有一種歸檔日誌文件。

oracle數據庫裏面有很多日誌
[oracle@redhat4 jiagulun]$ ls
control01.ctl  example01.dbf  redo03.log    temp01.dbf
control02.ctl  redo01.log     sysaux01.dbf  undotbs01.dbf
control03.ctl  redo02.log     system01.dbf  users01.dbf

可看到數據庫裏面有很多.log日誌。

oracle有redolog,它又分成多組,默認分成三組
首先oracle使用第一組日誌,往裏記日誌,時間長了第一個日誌文件滿了。
它開始用第二組,第二組滿了用第三組,
第三組滿了它反過來用第一組。
就把第一組覆蓋了。

oracle最多隻能保持三組日誌。
想保留更多的日誌,
因爲日誌的作用有很多,
oracle就產生了一個歸檔的一個工作模式。

先寫第一組日誌,寫滿了這時候
oracle會啓動一個進程叫ARCn。
這個進程會把日誌歸檔到另外一個目錄底下去,另外起一個名字,
大小和它一樣。
然後開始寫第二個日誌log文件,第二個寫滿切到第三個的時候,
這個進程把第二個log日誌寫到歸檔到的那個目錄下。
然後寫第三個、第四個。

在歸檔這個位置,
保留了oracle所有的日誌
我們要找較早的數據較早的日誌會從歸檔中找。

我們通過講一條sql語句,
講了從請求進來到獲取數據到返給用戶的一個工作流程。

進一步的oracle實例結構,給大家粗略的講了一下,後面還會詳細的講。

六)buffercache中的數據塊
服務器進程它首先會從數據庫數據文件裏面讀數據出來,
同時服務器進程找數據的時候首先在內存裏面找,在buffercache裏面找。
服務器進程還會修改裏面的數據。

修改完的數據是DBWn負責寫;
服務器進程它會對buffercache進行讀進行寫,對磁盤數據文件只進行讀。

buffercache寫回數據文件需要DBWn。

緩衝區裏面的數據,有幾種情況。
已連接
乾淨
空閒或未使用


dbf中的數據讀到內存SGA,
buffercache中的數據和磁盤dbf文件中的數據是一致的,
叫這個數據是乾淨的。

裏面還有一些內存空間沒有使用
這是空閒或未使用的。

還有對這個數據塊,
serverprocess在內存裏面把它的數據修改了,
內存裏面的數據,和磁盤中的數據就不一致了。
這時的內存裏面的數據叫髒數據。

髒數據就需要寫回dbf文件。
寫回來以後它倆又一致了,又成乾淨數據了。

還有在內存裏面的數據
目前serverprocess正在對它讀或者正在對它進行寫,
那個瞬間,這個數據塊叫pin住了。
翻譯叫連接了。
寫完以後馬上成了髒數據了。

PIN是讀寫一瞬間,
對內存的讀寫瞬間速度非常快。

已連接就是pin住。

隨着數據庫的運行,
buffercache慢慢在被使用,
其內數據塊有髒的、乾淨的、空閒的

再次把dbf中的一個數據調到內存的時候,它優先使用空閒的沒使用過的。

如果buffercache中所有的數據都使用過了,沒有空閒的,
它接着使用乾淨的。
因爲乾淨的數據意味着磁盤上有一個和它一樣的數據。
這樣新數據可以覆蓋掉乾淨的塊。
再需要原來乾淨數據塊時,可以再把原乾淨數據調入內存。

也就是說對buffercache來講
乾淨的或者空閒的這些數據,內存數據是可以被重用的。

對髒的能不能不直接覆蓋?
不能!

我們爲了使用這個髒的數據塊佔用的內存空間,
比如說裏面全是髒的,
我還需要再使用內存的時候,
就會觸發DBWn,將髒塊寫回磁盤。
寫回磁盤後原塊就成乾淨的了,
乾淨的就可以被重用了。

這是buffercache中數據塊的幾個狀態。

七)總結
前面給大家講了一條sql語句進入oracle的一個整體的執行流程。

進一步將數據庫的內存和進程結構,
以及一些物理結構的一些信息給大家講了。

這就是oracle的一個整體的體系結構。

以後的課我們一塊塊的去講。
包括物理結構、內存結構、進程結構等。
內存結構裏面還有一塊塊內容,我們也會分開去講。

oracle本身是計算機的一個軟件,
和其它軟件的結構其實是一樣的,儘管某些部分各有各的特點。

計算機程序的結構,
只包括兩部分:
數據部分 和 處理數據的代碼。
這兩個部分再根據需要和程序的目的,發生不同的變化。

程序最終的目的都是爲了處理數據。

數據庫的數據部分所佔比例較大,
一般程序數據部分所佔比例較小,
但都是爲了處理它。

程序員把絕大部分精力都放在了代碼上,但都是爲了呈獻最終的數據。



2016年7月17日 


文字:韻箏
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章