內容來源:2017 年 04 月 08 日,ITPUB管理版版主呂海波在“DBGeeK+PG資料庫技術沙龍(4月杭州站)”進行《Oracle中最容易被忽略的那些實用特性》演講分享。IT 大咖說(微信id:itdakashuo)作為獨家視訊合作方,經主辦方和講者審閱授權釋出。
閱讀字數:5457 | 14分鐘閱讀
摘要
本次演講主要圍繞Oracle的幾個特性展開,包括多租戶、In-Memory Option、多LGWP、邏輯讀優化。
雲端資料庫:多租戶
多租戶在Oracle中正式名稱是Multitenant Architecture,它包含兩個比較重要的概念CDB和PDB。CDB中的C是Container,因此又被稱為容器資料庫,PDB的P是Plugged,所以被稱為可插拔資料庫。
簡單來說,多租戶就是在一個資料庫塞多個資料庫。CDB作為一個母體,可以有N個PDB,且至少有1個PDB。所有PDB共享同一個SGA,和一系列的後臺程式。在Oracle中記憶體加程式被稱為例項,也就是說對外是一個例項,下方則是多個資料庫。雖然PDB和MySQL的Database看起來類似,但是區別其實非常大。最大的不同在於PDB之間是相對獨立的,有獨立的SYSTEM和資料檔案,在oracle 12c release 2中UNDO和Redo File也是獨立的。當CDB是OPEN狀態時,每個CDB可以是MOUNT、OPEN、OPEN Read Only三種狀態其中之一。
其實我們可以將CDB、PDB、多租戶理解為對Oracle表空間遷移的延伸,其主要目的就是為了讓資料庫獨立,使得遷移更方便。Oracle中表空間遷移有很多的依賴關係,比如A表空間中存在B表空間的索引之類的,所以在遷移的時候不光要遷移目標表空間,還要遷移所依賴的表空間。而在多租戶中PDB是隔離的,因此能夠很容易進行遷移。
CDB$ROOT
在CDB中有一個CDB$ROOT的根PDB,它是一個獨立資料庫。它的資料字典中包含其他PDB的資訊,所以拔出某個PDB,可以說是從一個CDB的CDB$ROOT中拔出。CDB$ROOT中的配置,就是所有PDB的預設配置。修改CDB$ROOT 中的引數、配置,就是在整個CDB級修改。Oracle準備了一個儲存所有PDB資訊的資料字典檢視dba_pdbs,通過它就可以查詢當前一共有多少PDB。
select pdb_id, pdb_name, dbid, con_uid, guid, status, con_id from dba_pdbs複製程式碼
上圖是通過這條SQL語句獲得的查詢結果。可以看到這裡面是不包含CDB$ROOT的,其實這個母體是存在的,但是Oracle為了避免誤操作將它給隱藏了。
PDB_PDB$SEED
除了CDB$ROOT,還有一個PDB_PDB$SEED——種子PDB,它只能以只讀模式開啟,不能手動關閉,只能隨CDB$ROOT一起開啟或關閉。它讓你能夠直接通過Clone PDB$SEED來建立新資料庫。它只包含SYSTEM表空間和SYSAUX表空間,而且我們不能增減它的表空間,也不能在它裡面建立表、索引等對 象。同時PDB$SEED只用來作Clone操作時的源,無法對它進行任何操作。
多租戶:建立CDB
建立CDB有兩種方式。一種是使用DBCA,目前都建議使用這種方式。一種手動建立。
上圖是手動建立的步驟,要注意的是標紅區域。其中enable pluggable database用來啟用CDB,後面的部分是用來指定種子PDB的儲存位置。seed file_name_convert是兩個選項,SEED和FILE_NAME_CONVERT。建庫命令中所建立的SYSTEM、SYSAUX等等表 空間、資料檔案都屬於根PDB CDB$ROOT,seed選項是宣告建立PDB$SEED。Oracle會從CDB$ROOT Clone SYSTEM表空間和SYSAUX表空間來建立PDB$SEED,file_name_convert選項指定Clone表空間時新資料檔案的位置。此選擇的作用和用法類似Standby中的file_name_convert。
多租戶:建立新的PDB
在CDB中建立新PDB,只需要使用這條SQL語句
CREATE PLUGGABLE DATABASE pdbtest1 ADMIN USER dba1 IDENTIFIED BY a
file_name_convert=('/export/home/oradb/oradata/CDBV3/pdbseed/','/export/home/oradb/oradata/CDBV3/pdbtest1/')複製程式碼
該語句最後是宣告檔案位置,第一個位置引數是種子的檔案位置,第二個位置引數是性的PDB的檔案位置。
也可以使用下面這條語句來建立。
CREATE PLUGGABLE DATABASE pdbtest2 FROM pdbtest1
file_name_convert=('/export/home/oradb/oradata/CDBV3/pdbtest1/','/export/home/oradb/oradata/CDBV3/pdbtest2/');複製程式碼
與上一條語句不同,這裡是從某一個已經存在的PDB中克隆,所以第一個引數是PDB的位置引數。這種情況一般用來測試,測試的時候需要儘量真實的線上資料,在對線上PDB克隆之後,可以將克隆的PDB拔出再插到測試環境中。
多租戶:連線PDB
連線到PDB也有兩種方式。一種是先進入cdb$root,再alter session set container=....,進入指定PDB。這種方式類似於MySQL,先連線上去,再通過use選擇database。
第二種方式直接連線PDB(需要用到監聽),使用tns_name直接進入指定的PDB。
監控
Oracle監聽實際上是通過解析例項名來連線到某個資料庫。在多個PDB共用一個例項的情況下,Oracle有一個PMON程式針對公共的例項將多個PDB註冊成服務形式,連個某個PDB的時候,Oracle會經由對應關係來找到例項。
多租戶:資料字典檢視
Oracle與MySQL相比有一個很大的優勢,就是資料字典非常豐富。原先Oracle有三層檢視,分別是DBA系列檢視(檢視所有資料)ALL系列檢視(可運算元據),USER系列檢視(所屬使用者檢視)。現在在這三層之上多了一個CDB_系列檢視,功能與原先的DBA相同,而原先的DBA檢視降級到PDB這一層。
開啟和關閉PDB
現在如果使用bash-3.2$ sqlplus / as sysdba這樣的方式開啟資料庫,就只是開啟了CDB$ROOT和PDB$SEED,新建立的PDB是不會啟動。
而要想開啟其他PDB需要在開啟資料庫後啟動如下命令。
alter pluggable database PDB_NAME1[,PDB_NAME2,……] open [READ ONLY FORCE] [UPGRADE [RESTRICTED]]
alter pluggable database PDB_NAME1[,PDB_NAME2,……] close [immediate]複製程式碼
引數管理
整個CDB只有一個SPFILE引數檔案,有些引數在各個PDB中可以設定為不同值。Spfile中只儲存CDB的引數值(或者說只儲存CDB$ROOT的值),各PDB的引數值是儲存在CDB的資料字典中。如果在某一個pdb中create pfile from spfile,結果檔案中將只包含此pdb和CDB不同的引數(也就是單獨在此pdb中 修改了的引數)。
並非所有引數都能夠在PDB中修改,如記憶體相關引數,由於所有PDB會共享SGA,無法限制某個PDB的記憶體使用情況。因此,不必要也不能修改某個PDB的記憶體引數,只能在CDB$ROOT中修改(或者說,只能在CDB級別修改)。
表空間管理
可以在PDB中建立表空間,每個PDB中的資料檔案、表空間都是獨立的。多個PDB可以使用同 一表空間名。查詢DBA_檢視,只能看到當前PDB的資訊。
但如果在CDB$ROOT中查詢V$檢視,可以看到所有PDB中表空間的資訊。因此V$檢視中會增加CON_ID列,DBA_檢視中則沒有此列。這是因為每個PDB自己的SYSTEM表空間中儲存自己的資料字典,因此DBA_檢視只有某個PDB的資訊。而V$視 圖中的資訊則來自於控制檔案,控制檔案是所有PDB共享的。
使用者、角色、許可權
由於有了CDB和PDB,所以使用者被分為兩類,一類跨越所有PDB的使用者,也叫全域性使用者,一類只存在某個PDB內的Local使用者。Oracle中全域性使用者必須以c##開頭,需要注意的是雖然Public不以c##開頭,但它也是一個全域性使用者,在每個pdb中可以授於Public不同的許可權。
與使用者管理一樣,角色也有全域性和Local之分,同一Common role,在不同PDB中可以有不同的許可權。
全域性使用者在不同PDB中也可以有不同的許可權,通過CONTAINER=current|ALL可以控制許可權是針對當前PDB還是所有PDB。
NoCDB轉換成CDB
// 1、以受限模式開啟資料庫:
shutdown immediate;
startup restrict mount exclusive;
alter database open read only;
// 2、生成XML後設資料描述檔案:
begin
dbms_pdb.describe(PDB_DESCR_FILE => '/u02/noncdb/orcl.xml');
end;
// 3、建立PDB
create pluggable database orcl using '/u02/noncdb/orcl.xml' copy;
// 4、執行noncdb_to_pdb指令碼
alter session set container=orcl;
@?/rdbms/admin/noncdb_to_pdb.sq複製程式碼
In-Memory Option
In-Memory Option是Oracle 12C中的一個重要特性,它開闢了一塊大小1m的記憶體空間IMCU。表的資料以列為單位儲存在IMCU中,一個表至少佔一個IMCU。
開啟In-Memory Option,首先要設定In-Memory Option的大小,然後重啟下資料庫。
//這裡設定In Memory Area大小為100m
SQL> alter system set inmemory_size=100m scope=spfile;
//載入表到IM中:
SQL> alter table t2 inmemory;
//取消In-Memeroy Area中的表
SQL> alter table t2 no inmemory;複製程式碼
儲存索引
Oracle將每個IMCU中最小ID值和最大ID值,儲存到一塊專門的記憶體區域,這個記憶體區就是儲存索引。全表掃描的時候會先在儲存索引中過濾一遍,過濾出只需要掃描的IMCU,比如查詢條件是ID>20 and ID<=100的列值,圖中第二個IMCU中,ID值的範圍是410~600,它就將被過濾掉。
多LGWR
Oracle的LGWR程式是用來將Log Buffer中的快取寫入檔案中。一直到oracle 11g release 2版本LGWR程式都只能有一個,單程式在壓力高的時候是會有延遲的,多LGWR有效的環節了這一問題。
多LGWR模式下LGWR不再進行寫操作,而是交給了LG0和LG1程式(優先使用LG)。在Log Buffe中有多個子池,一般只要其中的某一個子池資料超過三分之一,LWGR就會認為負載足夠大了,這是會啟用LG1。
多LGWR模式下存在一種特殊情況,即LG1先完成了I/O,但事務還有部分Redo沒有寫到磁碟,這時LG1會等待“ LGWR intra group sync”事件。前臺程式將繼續等待 Log File Sync。
邏輯讀時鎖的變化
邏輯讀在Oracle和MySQL中很相似,右下方區域在Oracle中被稱為塊,儲存著實際資料。
邏輯讀中會先根據塊的編號之類的資訊進行hash運算找到連結串列,再在連結串列中搜尋對應的資料結構,資料結構中就存放著塊的記憶體地址。整個過程中很多共享資源需要鎖來保護,所以邏輯讀的效能和併發主要就是看鎖的設計。
在MySQL中是不保護hash表的,它保護的是連結串列、buf_block_t以及下方的塊。而Oracle中則是多個連結串列(一般為4、5個)由1個鎖保護。
(獨佔模式)
(共享模式)
Oracle通過CBC Latch來保護連結串列,要訪問連結串列需要先獲得它,然後搜尋連結串列找到某一個BH,最後在BH中獲得BA地址。在以前的版本中CBC Latch只有持有和不持有模式,也就是說沒有共享的情況,直到最新版本中才有了共享、獨佔模式。
共享模式主要是通過在BH中新增Fast CR PIN來實現,每多一個人讀,引用計數就會加一。
新的機制查詢操作時鎖開銷更低,讀與讀完全不再阻塞,提高併發,CBC Latch競爭是Select與DML和CR塊間的競爭。Select間不會再有CBC Latch競爭。競爭優化的重點是縮短DML執行時間、減少事務持續時間(儘快提交)。