Oracle數(shù)據(jù)庫進程之服務器進程詳解
我們知道,Oracle數(shù)據(jù)庫中的各個進程要完成某個特定的任務或一組任務,每個進程都會分配內(nèi)部內(nèi)存(PGA 內(nèi)存)來完成它的任務。Oracle實例主要有3類進程:服務器進程、后臺進程和從屬進程,本文我們主要介紹一下Oracle數(shù)據(jù)庫服務器進程的相關知識,關于后臺進程和從屬進程我們會在后面的文章中繼續(xù)介紹。
Oracle實例主要有3 類進程:
(1)服務器進程(serverprocess):這些進程根據(jù)客戶的請求來完成工作。我們已經(jīng)對專用服務器和共享服務器有了一定的了解。它們就是服務器進程。
(2)后臺進程(backgroundprocess):這些進程隨數(shù)據(jù)庫而啟動,用于完成各種維護任務,如將塊寫至磁盤、維護在線重做日志、清理異常中止的進程等。
(3)從屬進程(slaveprocess):這些進程類似于后臺進程,不過它們要代表后臺進程或服務器進程完成一些額外的工作。
在某些操作系統(tǒng)(如Windows)上,Oracle使用線程實現(xiàn),所以在這種操作系統(tǒng)上,就要把我們所說的“進程”理解為“線程”的同義詞。
“進程”一詞既表示進程,也涵蓋線程。如果你使用的是一個多進程的Oracle 實現(xiàn),比如說UNIX 上的Oracle 實現(xiàn),“進程”就很貼切。如果你使用的是單進程的Oracle 實現(xiàn),如Windows上的Oracle 實現(xiàn),“進程”實際是指“Oracle 進程中的線程”。所以,舉例來說,當我談到DBWn 進程時,在Windows 上就對應為Oracle 進程中的DBWn 線程
服務器進程
服務器進程就是代表客戶會話完成工作的進程。應用向數(shù)據(jù)庫發(fā)送的SQL 語句最后就要由這些進程接收并執(zhí)行。
(1)專用服務器(dedicatedserver)連接,采用專用服務器連接時,會在服務器上得到針對這個連接的一個專用進程。數(shù)據(jù)庫連接與服務器上的一個進程或線程之間存在一對一的映射。
(2)共享服務器(sharedserver)連接,采用共享服務器連接時,多個會話可以共享一個服務器進程池, 其中的進程由Oracle 實例生成和管理。你所連接的是一個數(shù)據(jù)庫調(diào)度器(dispatcher),而不是特意為連接創(chuàng)建的一個專用服務器進程。
注意連接和會話之間的區(qū)別:
(1)連接(connection)就是客戶進程與Oracle 實例之間的一條物理路徑(例如,客戶與實例之間的一個網(wǎng)絡連接)。
(2)會話(session)則不同,這是數(shù)據(jù)庫中的一個邏輯實體,客戶進程可以在會話上執(zhí)行SQL 等。多個獨立的會話可以與一個連接相關聯(lián),這些會話甚至可以獨立于連接存在。
專用服務器進程和共享服務器進程的任務是一樣的:要處理你提交的所有SQL。當你向數(shù)據(jù)庫提交一個SELECT * FROM EMP 查詢時,會有一個Oracle 專用/共享服務器進程解析這個查詢,并把它放在共享池中(或者最好能發(fā)現(xiàn)這個查詢已經(jīng)在共享池中)。這個進程要提出執(zhí)行計劃,如果必要,還要執(zhí)行這個執(zhí)行計劃,可能在緩沖區(qū)緩存中找到必要的數(shù)據(jù),或者將數(shù)據(jù)從磁盤讀入緩沖區(qū)緩存中。這些服務器進程是干重活的進程。在很多情況下,你都會發(fā)現(xiàn)這些進程占用的系統(tǒng)CPU 時間最多,因為正是這些進程來執(zhí)行排序、匯總、聯(lián)結(jié)等等工作,幾乎所有工作都是這些進程做的。
專用服務器連接
在專用服務器模式下,客戶連接和服務器進程(或者有可能是線程)之間會有一個一對一的映射。如果一臺UNIX 主機上有100 條專用服務器連接,就會有相應的100 個進程在執(zhí)行??梢杂脠D來說明,如圖5-1 所示。
客戶應用中鏈接著Oracle 庫,這些庫提供了與數(shù)據(jù)庫通信所需的API。這些API 知道如何向數(shù)據(jù)庫提交查詢,并處理返回的游標。它們知道如何把你的請求打包為網(wǎng)絡調(diào)用,專用服務器則知道如何將這些網(wǎng)絡調(diào)用解開。這部分軟件稱為Oracle Net,不過在以前的版本中可能稱之為SQL*Net 或Net8。這是一個網(wǎng)絡軟件/協(xié)議,Oracle 利用這個軟件來支持客戶/服務器處理(即使在一個n 層體系結(jié)構(gòu)中也會“潛伏”著客戶/服務器程序)。不過,即使從技術上講沒有涉及Oracle Net,Oracle 也采用了同樣的體系結(jié)構(gòu)。也就是說,即使客戶和服務器在同一臺機器上,也會采用這種兩進程(也稱為兩任務)體系結(jié)構(gòu)。
這個體系結(jié)構(gòu)有兩個好處:
(1)遠程執(zhí)行(remoteexecution):客戶應用可能在另一臺機器上執(zhí)行(而不是數(shù)據(jù)庫所在的機器),這是很自然的。
(2)地址空間隔離(addressspace isolation):服務器進程可以讀寫SGA。如果客戶進程和服務器進程物理地鏈接在一起,客戶進程中一個錯誤的指針就能輕松地破壞SGA 中的數(shù)據(jù)結(jié)構(gòu)。
共享服務器連接
共享服務器連接強制要求必須使用Oracle Net,即使客戶和服務器都在同一臺機器上也不例外。如果不使用OracleTNS 監(jiān)聽器,就無法使用共享服務器。如前所述,客戶應用會連接到Oracle TNS 監(jiān)聽器,并重定向或轉(zhuǎn)交給一個調(diào)度器。調(diào)度器充當客戶應用和共享服務器進程之間的“導管”。圖5-2 顯示了與數(shù)據(jù)庫建立共享服務器連接時的體系結(jié)構(gòu)。
在此可以看到,客戶應用(其中鏈接了Oracle 庫)會與一個調(diào)度器進程物理連接。對于給定的實例,可以配置多個調(diào)度器,但是對應數(shù)百個(甚至數(shù)千個)用戶只有一個調(diào)度器的情況并不鮮見。調(diào)度器只負責從客戶應用接收入站請求,并把它們放入SGA 中的一個請求隊列。第一個可用的共享服務器進程(與專用服務器進程實質(zhì)上一樣)從隊列中選擇請求,并附加相關會話的UGA(圖5-2 中標有“S”的方框)。共享服務器處理這個請求,把得到的輸出放在響應隊列中。調(diào)度器一直監(jiān)視著響應隊列來得到結(jié)果,并把結(jié)果傳回給客戶應用。就客戶而言,它分不清到底是通過一條專用服務器連接還是通過一條共享服務器連接進行連接,看上去二者都一樣,只是在數(shù)據(jù)庫級二者的區(qū)別才會明顯。
連接與會話
在一條連接上可以建立0 個、一個或多個會話。各個會話是單獨而且獨立的,即使它們共享同一條數(shù)據(jù)庫物理連接也是如此。一個會話中的提交不會影響該連接上的任何其他會話。實際上,一條連接上的各個會話可以使用不同的用戶身份。
在Oracle 中,連接只是客戶進程和數(shù)據(jù)庫實例之間的一條特殊線路,最常見的就是網(wǎng)絡連接。這條連接可能連接到一個專用服務器進程,也可能連接到調(diào)度器。如前所述,連接上可以有0 個或多個會話,這說明可以有連接而無相應的會話。另外,一個會話可以有連接也可以沒有連接。使用高級Oracle Net 特性(如連接池)時,客戶可以刪除一條物理連接,而會話依然保留(但是會話會空閑)??蛻粼谶@個會話上執(zhí)行某個操作時,它會重新建立物理連接。
連接(connection):連接是從客戶到Oracle 實例的一條物理路徑。連接可以在網(wǎng)絡上建立,或者通過IPC 機制建立。通常會在客戶進程與一個專用服務器或一個調(diào)度器之間建立連接。不過,如果使用Oracle 的連接管理器(Connection Manager ,CMAN),還可以在客戶和CMAN之間以及CMAN 和數(shù)據(jù)庫之間建立連接。
會話(session):會話是實例中存在的一個邏輯實體。這就是你的會話狀態(tài)(session state),也就是表示特定會話的一組內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)。提到“數(shù)據(jù)庫連接”時,大多數(shù)人首先想到的就是“會話”。你要在服務器中的會話上執(zhí)行SQL、提交事務和運行存儲過程??梢允褂肧QL*Plus 來看一看實際的連接和會話是什么樣子,從中還可以了解到,實際上一條連接有多個會話的情況相當常見。
這里使用了AUTOTRACE 命令,并發(fā)現(xiàn)有兩個會話。我們在一條連接上使用一個進程創(chuàng)建了兩個會話。以下是其中的第一個會話:
- SQL> select username, sid, serial#, server,paddr, status from v$session where username='SYS';
- USERNAME SID SERIAL# SERVER PADDR STATUS
- ------------------------------ -------------------- --------- -------- --------
- SYS 153 27 DEDICATED 3621B264 ACTIVE
以上PADDR 列是這個專用服務器進程的地址。
下面,只需打開AUTOTRACE來查看SQL*Plus 中所執(zhí)行語句的統(tǒng)計結(jié)果:
- SQL> set autotrace on statistics
- SQL> select username, sid, serial#,server, paddr, status from v$session where username='SYS';
- USERNAME SID SERIAL# SERVER PADDR STATUS
- ------------------------------ -------------------- --------- -------- --------
- SYS 152 88 DEDICATED 3621B264 INACTIVE
- SYS 153 27 DEDICATED 3621B264 ACTIVE
- Statistics
- ----------------------------------------------------------
- 0 recursive calls
- 0 db block gets
- 0 consistent gets
- 0 physical reads
- 0 redo size
- 770 bytes sent via SQL*Net toclient
- 385 bytes received via SQL*Netfrom client
- 2 SQL*Net roundtrips to/fromclient
- 0 sorts (memory)
- 0 sorts (disk)
- 2 rows processed
此時有了兩個會話,但是這兩個會話都使用同一個專用服務器進程,從它們都有同樣的PADDR 值就能看出這一點。從操作系統(tǒng)也可以得到確認,因為沒有創(chuàng)建新的進程,對這兩個會話只使用了一個進程(一條連接)。
需要注意,其中一個會話(原來的會話)是ACTIVE(活動的)。這是有道理的: 它正在運行查詢來顯示這個信息,所以它當然是活動的。但是那個INACTIVE(不活動的)會話呢?那個會話要做什么?這就是AUTOTRACE 會話,它的任務是“監(jiān)視”我們的實際會話,并報告它做了什么。
在SQL*Plus 中啟用(打開)AUTOTRACE 時,如果我們執(zhí)行DML 操作(INSERT、UPDATE、DELETE、SELECT和MERGE),SQL*Plus 會完成以下動作:
(1)如果還不存在輔助會話[1],它會使用當前連接創(chuàng)建一個新會話。
(2)要求這個新會話查詢V$SESSTAT視圖來記住實際會話(即運行DML的會話)的初始統(tǒng)計值。
(3)在原會話中運行DML 操作。
(4)DML 語句執(zhí)行結(jié)束后,SQL*Plus會請求另外那個會話(即“監(jiān)視”會話)再次查詢V$SESSTAT,并生成前面所示的報告,顯示出原會話(執(zhí)行DML 的會話)的統(tǒng)計結(jié)果之差。
如果關閉AUTOTRACE,SQL*Plus 會終止這個額外的會話,在V$SESSION 中將無法看到這個會話。你可能會問:“SQL*Plus 為什么要這樣做,為什么要另建一個額外的會話?”。原因是:如果使用同一個會話來監(jiān)視內(nèi)存使用,那執(zhí)行監(jiān)視本身也要使用內(nèi)存。
如果在同一個會話中觀察統(tǒng)計結(jié)果,就會對統(tǒng)計結(jié)果造成影響(導致對統(tǒng)計結(jié)果的修改)。倘若SQL*Plus使用一個會話來報告所執(zhí)行的I/O 次數(shù),網(wǎng)絡上傳輸了多少字節(jié),以及執(zhí)行了多少次排序,那么查看這些詳細信息的查詢本身也會影響統(tǒng)計結(jié)果。這些查詢可能自己也要排序、執(zhí)行I/O 以及在網(wǎng)絡上傳輸數(shù)據(jù)等(一般來說都會如此?。?。因此,我們需要使用另一個會話來正確地測量。
到目前為止,我們已經(jīng)看到一條連接可以有一個或兩個會話?,F(xiàn)在,我們想使用SQL*Plus 來查看一條沒有任何會話的連接。這很容易。在上例所用的同一個SQL*Plus 窗口中,只需鍵入一個“很容易誤解”的命令即DISCONNECT:
ops$tkyte@ORA10G> set autotrace off
ops$tkyte@ORA10G> disconnect
從技術上講,這個命令應該叫DESTROY_ALL_SESSIONS 更合適,而不是DISCONNECT,因為我們并沒有真正物理地斷開連接。
注意在SQL*Plus 中要真正地斷開連接,應該執(zhí)行“exit”命令,因為你必須退出才能完全撤銷連接。不過,我們已經(jīng)關閉了所有會話。
使用另一個用戶賬戶打開另一個會話,并查詢原用戶SYS。
- SQL> select username, sid, serial#,server, paddr, status from v$session where username='SYS';
- no rows selected
可以看到,這個賬戶名下沒有會話,但是仍有一個進程,相應地有一條物理連接(使用前面的ADDR值):
- SQL> select username, program fromv$process where addr = hextoraw('3621B264');
- USERNAME PROGRAM
- ---------------------------------------------------------------
- oracle oracle@db1 (TNS V1-V3)
所以,這就有了一條沒有相關會話的“連接”。可以使用SQL*Plus 的CONNECT 命令(這個命令的名字也起得不恰當),在這個現(xiàn)有的進程中創(chuàng)建一個新會話(CONNECT命令叫CREATE_SESSION更合適):
- SQL> conn / as sysdba;
- Connected.
- SQL> select username, sid, serial#,server, paddr, status from v$session where username='SYS';
- USERNAME SID SERIAL# SERVER PADDR STATUS
- ------------------------------ -------------------- --------- -------- --------
- SYS 158 34 DEDICATED 3621B264 ACTIVE
可以注意到,PADDR 還是一樣的,所以我們還是在使用同一條物理連接,但是(可能)有一個不同的SID。我說“可能有”,是因為也許還會分配同樣的SID,這取決于在我們注銷時是否有別人登錄,以及我們原來的SID 是否可用。
到此為止,這些測試都是用一條專用服務器連接執(zhí)行的,所以PADDR 正是專用服務器進程的進程地址。
關于Oracle數(shù)據(jù)庫服務器進程的相關知識就介紹到這里了,希望本次的介紹能夠?qū)δ兴斋@!
【編輯推薦】






