Oracle Database 12cR2多租戶權威指南

qinghuawenkang發表於2018-10-24


Oracle Database 12cR2
多租戶權威指南
[紐西蘭]
[捷 克]
[瑞 士]
安東·艾爾斯(Anton Els)
維特·斯普林克(Vít Špinka)
弗蘭克·帕丘特(Franck Pachot)

史躍東 譯
北 京

Anton Els,Vít Špinka,Franck Pachot
Oracle Database 12c Release 2 Multitenant
EISBN 978-1-25-983609-1
Copyright © 2017 by McGraw-Hill Education.
All rights reserved. No part of this publication may be reproduced or transmitted in any form or by any
means, electronic or mechanical, including without limitation photocopying, recording, taping, or any
database, information or retrieval system, without the prior written permission of the publisher.
This authorized Chinese translation edition is jointly published by McGraw-Hill Education and Tsinghua
University Press Limited. This edition is authorized for sale in the People’s Republic of China only,
excluding Hong Kong, Macao SAR and Taiwan.
Translation copyright © 2018 by McGraw-Hill Education and Tsinghua University Press Limited.
版權所有。未經出版人事先書面許可,對本出版物的任何部分不得以任何方式或途徑複製或傳播,
包括但不限於影印、錄製、錄音,或透過任何資料庫、資訊或可檢索的系統。
本授權中文簡體字翻譯版由麥格勞-希爾(亞洲)教育出版公司和清華大學出版社有限公司合作出版。
此版本經授權僅限在中國大陸區域銷售,不能銷往中國香港、澳門特別行政區和台灣地區。
版權©2018 由麥格勞-希爾(亞洲)教育出版公司與清華大學出版社有限公司所有。
北京市版權局著作權合同登記號 圖字: 01-2017-3077
本書封面貼有 McGraw-Hill Education 公司防偽標籤,無標籤者不得銷售。
版權所有,侵權必究。侵權舉報電話: 010-62782989 13701121933
圖書在版編目(CIP)資料
Oracle Database 12
c R2 多租戶權威指南 / (紐西蘭)安東·艾爾斯(Anton Els), (捷克)維特·斯
普林克(Vít Špinka), (瑞士)弗蘭克·帕丘特(Franck Pachot) 著;史躍東 譯. —北京:清華大學
出版社, 2018
書名原文: Oracle Database 12
c Release 2 Multitenant
ISBN 978-7-302-50251-7
Ⅰ. ①O… Ⅱ. ①安… ②維… ③弗… ④史… Ⅲ. ①關聯式資料庫系統-指南
Ⅳ. ①TP311.138-62
中國版本圖書館 CIP 資料核字(2018)第 103253 號

責任編輯: 王 軍 李維傑
封面設計: 牛豔敏
版式設計: 思創景點
責任校對: 曹 陽
責任印製:董 瑾
出版發行: 清華大學出版社
網 址: ,
地 址:北京清華大學學研大廈 A 座 郵 編: 100084
社 總 機: 010-62770175 郵 購: 010-62786544
投稿與讀者服務: 010-62776969, c-service@tup.tsinghua.edu.cn
質 量 反 饋: 010-62772015, zhiliang@tup.tsinghua.edu.cn
印 刷 者:北京鑫豐華彩印有限公司
裝 訂 者:三河市溧源裝訂廠
經 銷: 全國新華書店
開 本: 170mm×240mm 印 張: 23 字 數: 451 千字
版 次: 2018 年 6 月第 1 版 印 次: 2018 年 6 月第 1 次印刷
印 數: 1~3500
定 價: 79.80 元
———————————————————————————————————————————
產品編號: 074808-01

譯 者 序
本打算趁著農曆春節之前,利用調休的時間將這本 400 多頁的書翻譯完畢,
誰曾想諸事纏身,一頓忙活之後,也就到了年三十。於是這本書也就只能在春
節之後搞定了。
嚴格來說,這本書是去年 9 月時著手翻譯的,到 2018 年 2 月,又是 6 個月
的時間。回想起去年翻譯《雲端儲存 Oracle ASM 核心指南》時,也是斷斷續
續忙了 5 個月才完工。留意起來,才意識到翻譯這個活兒,真心是一項費時費
心的工作。平時工作繁忙,也只能擠出晚上或週末,抑或調休的時間進行翻譯。
並且書中很多詞句都要斟酌再三、反覆琢磨,才能夠將原文的意思準確表達出
來。自己寫書,是對自己會的知識進行梳理;而翻譯,則是研究自己不會的東
西。因此,從某種程度上來說,翻譯的過程,實質上也是學習新技術、新知識
的過程。
多租戶與 IMO 一道,並稱為 Oracle Database 12c 的兩大關鍵特性。此番有
幸從清華大學出版社拿到這本書的翻譯權,也是件值得高興的事情。只不過與

IMO 相關的一本書, 則被 Oracle 原廠拿去翻譯了。若是這兩本書都由筆者翻譯,
再加上前面的 ASM,豈不是完美?可惜。
多租戶技術,是 Oracle 自 12.1 版本開始引入的一項全新特性。它從根本上
改變了 Oracle 資料庫長久以來的體系結構,也是 Oracle 在這個風起雲湧的時代,
全面迎合雲端計算的具體表現。對於傳統的 Oracle DBA 來說,熟練掌握 12c 版本
中的這一新特性,已經是毋庸置疑的事情。
本書的封底,指出這本書由 OCM 專家團隊編寫,而實際上,翻閱了本書
前言的各位讀者就會知道,本書的三位作者均是 Oracle ACE。他們不僅有著多
年的實踐經驗,也在各大技術社群和相關會議上進行技術分享。由這樣的人撰
寫本書, 本書內容的實戰性可想而知。本書從多租戶的基本概念入手, 涵蓋 CDB
與 PDB 的建立和管理、網路與服務、安全、備份和恢復、資料移動以及多租戶
的諸多高階特性,尤其是深入探討了諸多技術在多租戶環境下和此前版本中的
不同之處,這對於我們的實際工作來說,顯然是極具價值的內容。
當然,依然要感謝所有在本書付梓出版的過程中給筆者提供幫助的各位人
士,正是你們一直以來的關心與幫助,筆者才能夠筆耕不輟、日日向前。
由於筆者才疏學淺,因此在本書的翻譯過程中註定會有些錯誤與不足之處,
各位讀者見到後,望不吝賜教。
史躍東
2018 年 2 月 22 日
作 者 簡 介
Anton Els 是一位 Oracle ACE,目前是 Dbvisit 軟體有限公司的高階副總裁。
Anton 在資料庫技術領域已經有超過 15 年的工作經驗,擅長 Oracle 資料庫、備
份和恢復、資料庫備庫、 Oracle Linux、虛擬化以及 docker 技術。 Anton 是獨立
Oracle 使用者組(Independent Oracle Users Group, IOUG)的活躍成員,同時也是新
西蘭 Oracle 使用者組(New Zealand Oracle Users Group, NZOUG)的副主席。 Anton
擁有 Oracle Database 11g OCM 證照,還擁有從 8i 到 12c 的全部 OCP 證照。同
時,他還擁有 Oracle Database 11g RAC 與 GI 管理員方向的 OCE 證照、 Red Hat
5 RHSA 證照,以及 Oracle Solaris 10 的 SCSA 證照。 Anton 經常出席相關工業
及使用者組會議,例如一些行業合作會議、在日本舉行的 Oracle OpenWorld 資料
庫技術專場會議、 NZOUG,以及亞太和拉美地區的 Oracle 技術網路(OTN)年
會等。可以訪問他的 Twitter(@aelsnz)或部落格()。
Vít Špinka 是一位 Oracle ACE-A, 目前是 Dbvisit 軟體有限公司的首席架構
師。 Vít 在資料庫技術領域也有超過 15 年的工作經驗,主要擅長 Oracle 資料庫
技術。 Vít 也是 IOUG 的活躍成員,並經常出席 Oracle OpenWorld、行業合夥

會議、UKOUG、DOAG 以及 NZOUG 的相關活動。Vít 擁有 Oracle Database 10g、
11g 以及 12c 的 OCM 證照,還擁有從 9i 到 12c 的 OCP 證照、Oracle Database 10g
RAC 管理員專家認證,以及 LPIC-2 Linux 網路專業認證。可以訪問他的
Twitter(@vitspinka)或部落格(http://vitspinka.blogspot.com)。
Franck Pachot 是一位 Oracle ACE 總監,目前是 dbi 服務公司(瑞士)的首席
顧問、培訓專家以及 Oracle 技術領導人。 Franck 在 Oracle 技術領域擁有超過
20 年的工作經驗。 Franck 也經常參加 Oracle OpenWorld、 IOUG 合作會議、
DOAG、 SOUG 以及 UKOUG 的活動。他是 SOUG 和 DOAG 的活躍成員,同
時還是 OraWorld 團隊的榮譽成員。 Franck 擁有 Oracle Database 11g 和 12c 的
OCM 證照, 還擁有從 8i 到 12c 的所有 OCP 證照, 同時擁有 Oracle Database 12c
效能管理與最佳化方向的 OCE 證照。另外,他還擁有 Oracle Exadata Database
Machine 2014 實施認證證照。可以訪問他的 Twitter(@franckpachot)或部落格
(http://blog.pachot.net)。

技術編輯簡介
Deiby Gómez 是世界上最年輕的 Oracle ACE(23 歲)以及 ACE 總監(25 歲),
同時也是母國瓜地馬拉的第一位 ACE 和 ACE 總監,還是拉美地區最年輕(24
歲, 2015.2)的 Oracle 11g OCM 證照獲得者。他是瓜地馬拉第一位 OCM 證照獲
得者,另外也是最年輕(26 歲, 2016.4)的 Oracle 12c OCM 證照獲得者,是中央
美洲第一位 Oracle 12c OCM,是最近的 2016 年度編輯選擇大獎的獲得者(拉斯
維加斯,內華達州)。他經常在 Oracle 全球技術大會上發表演講,包括 2013 年
至 2016 年的 Oracle 技術網路拉丁美洲年會、合作會議(美國)以及 Oracle
OpenWorld 等。 Deiby 也是 Oracle 12cR2 beta 版本在瓜地馬拉的第一位測試者。
Deiby 分別用英文、西班牙文以及葡萄牙文發表過多篇技術文章,這些文章發
表在 Oracle 網站和 DELL’s Toad World 上。另外,在自己的部落格上,他也發表
過數百篇技術文章。他曾以傑出專家的身份出現在 2014 年 11 月份和 12 月份
的 Oracle 雜誌上。同時, Deiby 也是瓜地馬拉 Oracle 使用者組(GOUG)的主席、

拉美 Oracle 使用者組社群(LAOUC)的技術支援總監,他還是 OraWorld 團隊的共
同發起人。目前, Deiby 擁有自己的公司 NUVOLA,S.A,為拉美地區的客戶提供
Oracle 技術服務。
Arup Nanda 以 DBA 的身份工作超過 20 年,工作經驗幾乎涉及 Oracle 技
術的所有方面,從建模到效能調整,再到 Exadata 均有涉獵。他已經發表過大
約 500 篇文章,是 5 本書的合著者,發表過 300 多場演講。其部落格網站為 arup.
blogspot.com,他也是新手技術導師,是一名經驗豐富的 DBA。他曾於 2003 年
獲得過 Oracle 年度 DBA 大獎,在 2012 年獲得過年度企業架構師大獎。他也是
一位 ACE 總監,同時也是 Oak Table 網路的成員。

技術和語言編輯簡介
Mike Donovan 於 2007 年加入 Dbvisit,在該公司, Mike 扮演了多個角色,
包括擔任全球支援團隊的領導人以及數字業務開發先驅。並且就在最近,他成
為該公司的 CTO。 Mike 對新技術有著狂熱的激情,他與客戶及合作伙伴一起
工作,努力搭建資料庫技術與大資料等前沿技術之間的橋樑,從而創造出商業
價值。他喜歡接受挑戰,會嘗試探求更智慧、更低成本的解決方案或替代方案。
Mike 具有技術、藝術以及客戶支援和軟體開發等多方面的複合背景。他對
Oracle 資料庫技術極有熱情,併為之工作超過 10 年的時間。他也在多個行業會
議上發表演講,包括 OOW、 RMOUG、日本資料技術會議以及合作會議等。
Mike 作為產品 DBA 工作多年,獲得了從 9i 到 12c 的多項認證。

前 言
在 Oracle Database 12cR1 版本(12.1)中, 開始引入名為“多租戶”的新選項。
從那時起,新的術語“可插拔資料庫”便傳播開來。但是這個術語,往往意味
著對該特性或其影響並沒有清晰的理解。從 12c 的第一個版本開始,多租戶已
經是 Oracle 資料庫中最為重大的架構變革之一,同時該選項在資料庫軟體中已
經被落地實施。多租戶選項帶來了很多新的特性,但也影響到了 Oracle DBA
進行日常管理的方式。從 12c 的第二個版本(12.2)開始,對多租戶選項的可用特
性進行了更多的擴充套件。現在比較清楚的一點就是,舊的系統架構已經被拋棄,
多租戶則已經開始生根發芽——不容忽視。
12cR2 中多租戶的到來,需要 DBA 調整他們現有的思考方式,以及進行日
常管理的方式。無論是執行單租戶資料庫,還是執行包含大量租戶的資料庫,
都需要經歷一個新的學習過程。所以,相比於單純描述多租戶這個新東西究竟
包含了什麼內容,本書更傾向於描述與 DBA 相關的工作究竟發生了怎樣的變
化,無論是核心的日常維護操作,還是一些相關的高階特性。可以將本書視為
Oracle Database 12c 的管理指南。此外,還可以學到關於這些新特性的一些實

戰知識,包括語法上的改變,以及最佳實踐等方面的內容。本書由三位具有豐
富 DBA 經驗並具備相關認證的 DBA 撰寫,並經由諸多技術精湛的稽核人員進
行嚴格審查,從而使內容的價值得到進一步的提升。唯有如此,才能讓你帶著
洞察一切的激情來了解 Oracle 資料庫的管理工作。
本書第Ⅰ部分介紹多租戶的功能。其關鍵問題包括, Oracle 公司為何要引
入這一選項,並以何種方式來模仿其他資料庫產品,以及該選項是否能夠真正
為我們設計並部署應用的方式所需要。第 1 章專注這些問題並解釋多租戶架構。
第 2 章討論容器資料庫(CDB)的建立流程,以及如何正確完成這一流程。因為
在 12c 版本中,建立 CDB 已經是預設的選項,不管信不信,我們真的遇到一些
人在對 CDB 毫不知情的情況下就建立了 CDB。在對多租戶的各種特性進行詳
細描述之前,第 3 章會為你提供資訊,讓你決定究竟是選擇使用 CDB 還是非
CDB 資料庫,並且第 3 章還提供不同可用版本和選項的概要資訊。
第Ⅱ部分將會講述當使用多租戶特性時,你的日常工作將會發生怎樣的改
變。這一部分從第 4 章開始,該章關注 PDB 的建立與管理,並且也會涉及將數
據庫升級到 12c 版本的內容。第 5 章將會詳細討論資料庫的網路與服務。接下
來的第 6 章,則會關注另一個重要議題——安全——我們將探討 PDB 的隔離、
使用者的公共性以及加密。
第Ⅲ部分將會討論備份與複製操作等方面的巨大提升。當然,主要是在
PDB 級別。第 7 章將會詳細研究作為每一個 DBA 都應該足夠熟悉的領域——
備份和恢復——以及如果需要的話,如何將資料庫恢復到過去的某個狀態。第
8 章討論如何使用資料庫閃回技術實現歸檔,以及如何在 PDB 級別實現基於時
間點的恢復。本部分的最後一章,第 9 章將會研究如何插入/拔出 PDB,以及如
何對 PDB 進行克隆、傳輸或線上重定位(online relocation)。
在本書的第Ⅳ部分,你將會在一個新的層次或級別上學習多租戶。當對多
個 PDB 進行整合時,將不得不意識到資源管理器(Resource Manager, RM)的價
值。關於 RM,將在第 10 章進行討論。在多租戶環境中, RM 將會發揮極為重
要的作用。第 11 章將會關注如何使用 DG 來對多租戶資料庫進行保護。第 12
章將會討論 CDB 中的資料共享問題。與物理克隆或同步技術相比,基於雲的
解決方案,則需要資料能夠以一種更具靈活性的方式來提供。我們將在第 13
章討論邏輯複製的相關內容。

目 錄
第Ⅰ部分 多租戶意味著什麼
第 1 章 多租戶概述 ······················3
1.1 歷史課堂: IT 技術的
新時代·································4
1.1.1 通往多租戶之路············ 5
1.1.2 方案整合 ······················· 6
1.1.3 表整合 ··························· 9
1.1.4 伺服器整合 ··················· 9
1.1.5 虛擬化 ························· 10
1.1.6 一個例項管理多個
資料庫 ·························
10
1.1.7 整合策略總結·············· 11
1.2 系統字典與多租戶架構 ··· 11
1.2.1 過去:非 CDB············· 11
1.2.2 多租戶容器·················· 14
1.2.3 多租戶字典·················· 16
1.2.4 使用容器 ····················· 21
1.3 什麼是 CDB 級別的
整合···································27

1.4 本章小結 ··························33
第 2 章 建立資料庫 ····················35
2.1 建立容器資料庫(CDB) ····36
2.1.1 OMF 概述···················· 36
2.1.2 CDB 建立選項 ············ 37
2.2 建立可插拔資料庫
(PDB) ································52
2.2.1 使用 PDB$SEDD 建立
新的 PDB ····················
53
2.2.2 使用本地克隆方式建立
新的 PDB ····················
56
2.2.3 使用 SQL Developer
建立 PDB ····················
57
2.2.4 使用 DBCA 建立 PDB··· 60
2.2.5 使用 Cloud Control
建立 PDB ····················
61
2.3 使用 catcon.pl 指令碼 ··········62
2.4 本章小結 ··························64
第 3 章 單租戶、多租戶以及應用
容器·······························65
3.1 多租戶架構不是一個
選項 ··································66
3.1.1 拋棄非 CDB ················ 66
3.1.2 不相容特性 ················· 67
3.2 標準版中的單租戶···········68
3.2.1 資料移動 ····················· 68
3.2.2 安全 ····························· 69
3.2.3 與 SE2 整合················· 69
3.3 企業版中的單租戶···········70
3.3.1 閃回 PDB····················· 71
3.3.2 PDB 的最大數量 ········· 71
3.4 使用多租戶選項···············73
3.4.1 應用容器 ····················· 73
3.4.2 與多租戶選項整合 ······ 76
3.5 本章小結 ··························77
第Ⅱ部分 多租戶管理
第 4 章 日常管理 ·······················79
4.1 選擇要使用的容器···········81
4.2 管理 CDB ·························83
4.2.1 建立資料庫·················· 83
4.2.2 啟動與關閉資料庫 ······ 83
4.2.3 刪除資料庫·················· 84
4.2.4 修改整個 CDB············· 84
4.2.5 修改根容器·················· 85
4.3 管理 PDB··························86
4.3.1 建立新的 PDB ············· 86
4.3.2 開啟和關閉 PDB ········· 86
4.3.3 檢視 PDB 的狀態 ········ 90
4.3.4 檢視 PDB 的操作
歷史 ·····························
90
4.3.5 在多個 PDB 上執行
SQL······························
90
4.3.6 修改 PDB····················· 91
4.3.7 刪除 PDB····················· 93
4.4 打補丁與升級···················93
4.4.1 升級 CDB ···················· 94
4.4.2 插入 ·························· 103
4.4.3 打補丁 ······················ 105
4.5 使用 CDB 級別與 PDB 級別
的引數·····························106
4.5.1 CDB SPFILE············· 106
4.5.2 PDB SFPILE 的
等價性 ······················
106
目 錄 XIII
4.5.3 SCOPE=MEMORY ··· 108
4.5.4 ALTER SYSTEM
RESET·······················
108
4.5.5 ISPDB_MODIFIABLE··· 108
4.5.6 CONTAINER=ALL ··· 109
4.5.7 DB_UNQIUE_
NAME ·······················
110
4.6 本章小結 ························ 111
第 5 章 網路與服務 ··················113
5.1 Oracle Net ······················· 114
5.2 Oracle 網路監聽 ············· 114
5.3 LREG 程式 ····················· 115
5.4 網路:多執行緒與
多租戶····························· 117
5.5 服務名稱 ························ 119
5.5.1 預設服務與連線到
PDB ···························
119
5.5.2 建立服務 ··················· 122
5.6 為 PDB 建立專用監聽 ···127
5.7 本章小結 ························130
第 6 章 安全·····························131
6.1 使用者、角色以及許可權·····132
6.1.1 公共使用者還是本地
使用者? ·······················
132
6.1.2 何為使用者? ··············· 133
6.1.3 CONTAINER=
CURRENT·················
134
6.1.4 CONTAINER=
COMMON·················
135
6.1.5 本地授權 ··················· 138
6.1.6 公共授權 ··················· 139
6.1.7 衝突解決 ··················· 140
6.1.8 保持清晰與簡單······· 143
6.1.9 CONTAINER_
DATA························
143
6.1.10 角色 ························ 145
6.1.11 代理使用者················· 145
6.2 鎖定概要檔案
(lockdown profile)············147
6.2.1 禁用資料庫選項······· 148
6.2.2 禁用 ALYTER
SYSTEM···················
148
6.2.3 禁用特性 ·················· 150
6.3 PDB 隔離························150
6.3.1 PDB_OS_
CREDENTIALS········
150
6.3.2 PATH_PREFIX ········· 151
6.3.3 CREATE_FILE_
DEST ························
151
6.4 透明資料加密(TDE) ······151
6.4.1 建立 TDE·················· 152
6.4.2 帶有 TDE 的插入與克隆
操作 ··························
157
6.4.3 TDE 總結·················· 157
6.5 本章小結 ························157
第Ⅲ部分 備份、恢復與資料
庫移動
第 7 章 備份和恢復··················161
7.1 回到基礎知識·················162
7.1.1 熱備份與冷備份······· 162
7.1.2 RMAN:預設配置 ··· 164
7.1.3 RMAN 冗餘備份······ 165
7.1.4 SYSBACKUP 許可權··· 166
7.2 CDB 備份與 PDB 備份 ···166

7.2.1 CDB 備份 ·················· 167
7.2.2 PDB 備份··················· 171
7.2.3 別忘了歸檔日誌! ···· 174
7.3 恢復場景 ························174
7.3.1 例項恢復 ··················· 175
7.3.2 對 CDB 進行還原和
恢復···························
176
7.3.3 對 PDB 進行還原和
恢復···························
178
7.4 RMAN 最佳化方面的一些
考量·································180
7.5 資料恢復指導·················183
7.6 塊損壞 ····························184
7.7 使用 Cloud Control 進行
備份 ································184
7.8 本章小結 ························186
第 8 章 閃回與基於時間點的
恢復·····························189
8.1 PDB 的基於時間點的
恢復 ································190
8.1.1 在指定時間恢復
PDB ···························
191
8.1.2 UNDO 在哪裡? ······· 193
8.1.3 版本 12.1 中的
PDBPITR 總結 ··········
195
8.2 版本 12.2 中的本地
UNDO ·····························196
8.2.1 資料庫屬性 ··············· 197
8.2.2 建立資料庫 ··············· 197
8.2.3 修改 UNDO 表空間 ·· 198
8.2.4 修改 UNDO 管理
模式···························
199
8.2.5 共享 UNDO 還是本地
UNDO? ···················
200
8.3 版本 12.2 中 PDBPITR···201
8.3.1 共享 UNDO 模式下的
PDBPITR··················
201
8.3.2 本地 UNDO 模式下的
PDBPITR··················
202
8.4 閃回 PDB························202
8.4.1 閃回日誌 ·················· 203
8.4.2 使用本地 UNDO 進行
閃回 ··························
205
8.4.3 使用共享 UNDO 進行
閃回 ··························
205
8.4.4 CDB 和 PDB 級別的
還原點 ······················
206
8.4.5 乾淨還原點··············· 209
8.5 resetlogs ·························· 210
8.6 閃回與 PITR···················212
8.6.1 何時需要 PITR 或
閃回? ······················
212
8.6.2 對備庫的影響··········· 212
8.6.3 輔助例項的清除······· 214
8.7 本章小結 ························215
第 9 章 移動資料 ·····················217
9.1 錨定 PDB 檔案位置 ·······218
9.2 插入與拔出 ····················218
9.2.1 PDB 的拔出與插入 ·· 219
9.2.2 停留在源庫中的已拔出
資料庫 ······················
220
9.2.3 XML 檔案中究竟有
什麼? ······················
222
9.2.4 為插入操作檢查
相容性 ······················
225
目 錄 XV
9.2.5 像克隆一樣插入········ 226
9.2.6 PDB 的歸檔檔案 ······· 228
9.3 克隆 ································229
9.3.1 克隆本地 PDB··········· 229
9.3.2 克隆遠端 PDB··········· 231
9.4 應用容器的一些考量·····236
9.5 轉換非 CDB 資料庫·······236
9.5.1 插入非 CDB ·············· 237
9.5.2 克隆非 CDB ·············· 239
9.6 將 PDB 移動到雲上 ·······240
9.7 基於 PDB 操作的
觸發器·····························241
9.8 全傳輸匯出/匯入············241
9.9 可傳輸表空間·················244
9.10 本章小
結 ··························· 245
第Ⅳ部分 多租戶高階特性
第 10 章 Oracle 資料庫資源
管理器························249
10.1 資源管理器基礎···········250
10.1.1 資源管理器關鍵
術語 ·······················
251
10.1.2 資源管理器的
需求 ·······················
253
10.1.3 資源管理器的
級別 ·······················
253
10.2 CDB 資源計劃··············254
10.2.1 資源分配與使用
限制 ·······················
254
10.2.2 預設與自動任務
指令 ·······················
256
10.2.3 建立 CDB 資源
計劃 ·······················
257
10.3 PDB 資源計劃··············265
10.3.1 建立 PDB 資源
計劃 ······················
266
10.3.2 啟用或禁用 PDB 資源
計劃 ······················
268
10.3.3 移除 PDB 資源
計劃 ······················
269
10.4 使用初始化引數管理 PDB
的記憶體和 I/O ················269
10.4.1 PDB 的記憶體分配·· 269
10.4.2 限制 PDB 的 I/O··· 270
10.5 例項囚籠
(instance caging) ··········· 270
10.6 監控資源管理器···········272
10.6.1 檢視資源計劃與資源
計劃指令···············
272
10.6.2 監控被資源管理器
管理的 PDB ··········
273
10.7 本章小結 ······················274
第 11 章 Data Guard ···············275
11.1 ADG 選項·····················276
11.2 建立物理備庫···············277
11.2.1 使用 RMAN 進行
複製 ······················
277
11.2.2 使用 EMCC 建立
備庫 ······················
289
11.3 在多租戶環境下管理
物理備庫 ······················292
11.3.1 在源端建立新的
PDB ······················
293
11.3.2 將 PDB 從源端
刪除 ······················
294
11.3.3 修改子集 ·············· 295
11.3.4 EMCC···················· 298
11.4 雲上的備庫···················298
11.5 本章小結·······················301
第 12 章 在 PDB 之間共享
資料···························303
12.1 資料庫連結···················304
12.2 共享公共只讀資料·······305
12.2.1 可傳輸表空間········ 306
12.2.2 儲存快照與基於寫的復
制(copy on wirte) ···
307
12.3 跨 PDB 檢視·················308
12.3.1 簡單使用者表 ··········· 309
12.3.2 整合資料 ··············· 313
12.4 跨資料庫複製···············327
12.5 本章小結 ······················327
第 13 章 邏輯複製····················329
13.1 Oracle 日誌挖掘器
(LogMiner)····················331
13.2 已過期的特性···············332
13.2.1 Oracle CDC··········· 332
13.2.2 Oracle 流技術 ······· 332
13.2.3 Oracle 高階複製 ··· 332
13.3 OGG(Oracle
GoldenGate)··················333
13.3.1 OGG 中的多租戶
支援 ······················
333
13.3.2 大資料介面卡······· 343
13.4 Oracle XStream·············345
13.5 邏輯備庫 ······················346
13.6 其他第三方選項···········347
13.6.1 Dbvisit Replicate ··· 347
13.6.2 Dell SharePlex······· 347
13.7 本章小結 ······················347

多租戶意味著什麼

第 1 章
多租戶概述
在 Oracle Database 12c 中, Oracle 引入了一項發生於資料庫體系結構上的
重大調整。在 Oracle Database 12c 以前,一個例項只能開啟一個資料庫。如果
想處理多個資料庫,那麼需要啟動多個例項才行。因為它們都是完全隔離的架
構,即便這些資料庫都安裝在同一臺伺服器上也是如此。這一點與其他關係型
資料庫頗為不同,其他很多的資料庫,都是可以使用一個例項來管理多個資料
庫的。
進入 Oracle Database 12c 之後,一個例項就可以開啟多個可插拔資料庫,
或者稱之為 PDB(Pluggable DataBase)。 Oracle 將之稱為新多租戶架構,以前舊

的架構名稱便被拋棄了。無論是否使用了多租戶選項,將來所有的 Oracle 資料
庫都會執行在多租戶架構上。關於這點事實,所有的 DBA 都是不能忽視的。
1.1 歷史課堂: IT 技術的新時代
在介紹將來的架構之前,讓我們先簡要回顧一下使用資料庫的歷史。如你
在圖 1-1 中所看到的,我們並不關注時間,而是關注資料庫版本,透過它來回
顧 Oracle 資料庫的演化歷程。

圖 1-1 從 IT 整合到雲
當 Oracle Database 8i 和 9i 出現在市場上時, 資料中心使用中型機逐漸變得
流行起來。我們從大型機時代開始步入客戶端/伺服器時代。而當時的 Oracle
資料庫的體系結構,顯然是非常適應這一趨勢的。由於 Oracle 資料庫是使用 C
語言編寫的,因此它在多種平臺上均能成功運轉。並且,所有使用者管理資訊都
儲存在資料庫的資料字典中。 Oracle 資料庫顯然為客戶端/伺服器架構做好了準
備,它可以使用作業系統來監聽 TCP/IP 埠並儲存檔案。此外,資料庫的架構
在小型機上也是可擴充套件的,這多虧了一個被稱為並行伺服器的特性。當然,後
來它被稱為 RAC(Real Application Cluster)。
隨著伺服器數量的增長,資料庫的數量也隨著增長。在那時,一家公司往
往會擁有很多臺物理伺服器,並且使用 DAS(Direct Attached Disks,直連儲存)
作為儲存,而在每臺伺服器上,則又執行著 1 個或 2 個 Oracle Database8i 或 9i
例項。
隨著資料庫數量的增長,管理所有的伺服器和磁碟則又成為噩夢一般的存
在。面對著資料的指數級增長,還依然使用內部磁碟來管理這些資料的話,則
容量規劃就變得極其困難。此時, Oracle Database 10g 便應運而生。我們需要

對儲存進行整合,這樣我們就可以把資料庫檔案存放到一個儲存陣列中,並通
過 SAN(Storage Area Network, 儲存區域網路)讓所有的伺服器都可以共享訪問。
這就是儲存整合。
隨著時間的流逝, Oracle Database 11g 開始登場。早期,比較流行的想法
是,我們使用伺服器,然後每臺伺服器上都帶有磁碟。但是,相比於設定多臺
伺服器的容量並對其進行維護而言,虛擬化軟體則為我們提供了一種新的可能:
我們可以將多臺物理伺服器放在一起,並在此基礎之上提供虛擬機器。在以前的
時代,我們就是使用這樣的方法:應用伺服器、 SAN 或 NAS,以及虛擬機器。
現在, Oracle Database 12c 為我們帶來一種新的方法。很多擁有整合儲存
和伺服器的組織,目前已經意識到運營這樣的架構其實並非他們的核心業務。
相反,他們將 IT 需求視作一個服務,它應該具有可擴充套件性和靈活性。小公司想
要使用公有云來提供他們所需的 IT,大一些的公司則打算建立自己的私有云。
在這樣的情況下,虛擬化就可以提供 IaaS(Infrastructure as a Service,基礎設施
即服務)。但是,我們也需要 AaaS(Application as a Service,應用即服務)和
DBaaS(DataBase as a Service,資料庫即服務)。對於 IT 技術生態圈而言,這顯
然是一個極為重大的變化。 這與當年從客戶端/伺服器架構進化到應用伺服器時
代頗為相似,無論是擴充套件性方面還是重要性方面。當然,這一過程並非一蹴而
就——它需要時間。不過,現在就可以斷言,在接下來的十年中,混合模型(按
需供應/雲)將變得更強大,但是也終將會被雲慢慢替代。
正如我們所期待的,新的時代有著不同的需求。資料庫的未來也將與整合、
敏捷開發,以及快速就緒等聯絡在一起。對於 Oracle 而言,類似這樣的一些特
性,其實從 9i 到 11g 一直都處於快速進化之中。比如簡單資料傳輸、克隆,以
及精簡指令配置(thin provisioning)等。但是資料庫中的兩個核心架構功能:一
資料庫一例項,以及一資料庫一資料字典,一直以來都是如此,尚未做好整合
的準備。為此, Oracle Database 12c 提供了這兩個問題的答案:多租戶。在保
留原有可移植性架構的基礎之上, Oracle 對其架構進行了設計調整,從而使得
可以在同一個資料庫上執行應用——無論程式是執行在小型伺服器上,還是運
行在很大的雲上。
1.1.1 通往多租戶之路
新的時代是關於整合的時代。一些人會將其想象成一個集中式系統,並輔
以集中管理。但是這帶來了新挑戰:我們需要越來越高的敏捷性。讓一個數
據庫快速就緒在今天而言,本非一件容易之事。但至少,我們不能讓它變得
更糟糕。
考慮這樣一個例子。你是一個 Oracle DBA。然後一個開發人員來到你的辦
公桌前,並表示她需要一個新的資料庫。在她的意識裡,可能會認為這是一個

很簡單的需求,你只需要在一個管理介面上單擊幾下滑鼠應該就能搞定。你看
著她,瞪大眼睛,然後告訴她需要去填一張需求申請單,上面需要指定儲存、
記憶體、 CPU 以及可用性方面的內容。並且,你還得解釋,這樣的需求要上級領
導批准,需要花費數天甚至一週的時間才能建立一個資料庫。顯然,這裡就是
開發人員與運維人員之間通常會產生誤解的地方。
開發人員可能以前就沒有使用過 Oracle 資料庫, 所以她就閃過一些念頭,
認為資料庫不過就是用來裝她的應用程式表的一個容器罷了,並且這個容器
還是一個很輕量級的玩意——在很多其他的非 Oracle 資料庫中,這實際上就是
“資料庫”。
但是在 Oracle 中,恰恰相反,我們是有一些輕量級的容器——邏輯級別上
的方案(scheme),以及物理級別上的表空間(tablespace)——但是資料庫,則不僅
僅是這些內容的整個組合。 Oracle 資料庫,是一組方案和表空間的集合,然後
再加上用於管理這些內容的後設資料(資料字典),以及為數眾多的用於實施各種
特性的 PL/SQL 程式碼(DBMS 包)。每一個資料庫都必須擁有自己的例項,而實
例又由一組後臺程式和一塊共享記憶體構成。並且每一個資料庫也都有相應的結
構來保護事務的完整性,比如 UNDO 表空間和 REDO 日誌。
因此,基於上述這些理由,提供一個新的資料庫並不是件很瑣碎細微的事
情。要建立一個新的資料庫,需要與系統管理員和儲存團隊進行溝通,因為需
要伺服器和磁碟資源。你並不打算在一臺伺服器上部署太多例項,但是你也不
太可能在一臺伺服器上只部署一個資料庫。正是因為這些,現在我們通常使用
虛擬化技術,然後為每個例項提供一臺虛擬機器(Virtual Machine, VM)。當然,
這種方法並不適用於每一個應用或每一個環境,從敏捷的角度來看——因為這
樣的話,需要的虛擬機器就太多了。另外,當為每一個資料庫都不得不分配服務
器、儲存以及例項時,最終你就會發現,這樣浪費太多資源了。
在 Oracle Database 12c 以前,這種場景下,對於開發人員來說,比較合適
的方法,就是在現有的資料庫中為其建立新的方案。但是這種方法並不總是可
能的,或者說是可行的。讓我們解釋一下為什麼。
1.1.2 方案整合
在 Oracle Database 12c 以前,方案就是可用的解決方法。每一個應用程式
都可以有自己的方案,或是一組方案,如果想將表和儲存過程分開的話。這些
方案在邏輯上是隔離的,並使用許可權管理來保證其安全性。
從物理上來講,也可以為每個應用設定不同的表空間。這就意味著,一旦
資料檔案丟失,在還原期間,可能就只有一個應用處於離線狀態。如果想將表
空間重新分佈到其他檔案系統中,也是如此。但是,除此之外,為了最佳化資源
使用,其他的所有資源我們都是共享的:例項程式與記憶體、SYSTEM 與 SYSAUX

表空間、資料字典等。
備份策略和高可用(High Availability, HA)策略也都是相同的。一個 DBA
管理一個資料庫,然後在這個資料庫上執行多個應用。在 Oracle 資料庫的早期
版本中,資料庫就是按照這樣的方式來設計的。
1. 可傳輸表空間
在 Oracle 資料庫中,很多操作都是發生在表空間級別的。尤其是可傳輸表
空間這一特性。透過這一特性,可以將應用的資料檔案物理地複製到其他資料
庫中,即便是複製到一個更高版本的資料庫中也是可以的。可傳輸表空間這一
特性足夠重要,因為它被認為是多租戶技術的先驅,或者是始祖。1997 年, Oracle
公司為可傳輸表空間技術申請專利,名為“資料庫系統的可插拔表空間”。而現
在,多租戶架構恰恰就是可插拔資料庫的基礎。
在這裡,可插拔的意思,就是可以直接將一個物理結構(資料檔案)插到一
個資料庫中,並令其成為該資料庫的一部分。可傳輸表空間這一特性,就能夠
將使用者表空間的資料檔案插入到資料庫中。 然後就只需要匯入相應的後設資料(數
據字典實體)即可。這樣,在新的資料庫中,這些邏輯物件的定義就與資料檔案
中的物理內容相匹配了。
當然,在 Oracle Database 12c 中,也可以傳輸表空間,這樣的操作也足夠
簡單。如果想傳輸所有的使用者表空間,使用“FULL=Y”選項即可。但是相關
的後設資料還是需要被邏輯傳輸。如果有數百張表的後設資料需要傳輸,那麼這個
時間可能就會比較長。即便這些表都是空表也是如此。例如,如果想遷移一個
PeopleSoft 資料庫,它裡面包含 20 000+張表。即便這些表都是空的,匯入元數
據也需要幾個小時的時間。
正如你將看到的,由於多租戶更卓越的效能,傳輸一個可插拔資料庫,實
際上就成為所有資料檔案的傳輸,包括 SYSTEM 和 SYSAUX 中的資料檔案。
顯然,這裡面就包含了資料字典,甚至還可能包含 UNDO 資訊。這就意味著所
有的後設資料也將會被物理匯入。因此,相比傳統的可傳輸表空間技術,這樣的
操作就快了很多。
2. 方案名稱衝突
在真實世界中,想實現方案整合,其實還是很有難度的。你可能想將很多
應用都整合到一個資料庫中,甚至包括同一個應用的測試環境也想整合進來。
此時,就會面對一系列應用程式的約束問題。
如果應用中的方案所有者是硬編碼的,不能修改,那麼此時該怎麼辦?如
果我們需要建立一個電話清單系統,而該系統在資料庫中對應的方案為 PB,然
後我們想將多個環境都整合到測試資料庫中,那麼這顯然是被禁止的。原因是
該方案的名稱已經硬編碼到應用程式以及包中,當然還有其他地方。如果有應

用程式供應商派來的顧問,也許我們還能夠比較好地理解這些奇怪的方案名稱。
但是如果沒有,可能就得去猜測這些方案名稱最初究竟是什麼意思。
當然,如果應用是在你的掌控之下進行設計的,那麼你就可以避免這樣的
問題。並且無須多言,你應該在自己的應用程式中從來都不要對方案名稱進行
硬編碼。可以使用某一使用者連線到資料庫,然後簡單地使用 ALTER SESSION
SET CURRENT_SCHEMA 語句來設定當前應用程式的方案所有者,從而來訪
問所有相關的物件。如果有多個方案?那麼為應用程式使用多個方案倒也不算
是一個壞主意。
例如,可以使用程式碼(PL/SQL 包)來分離資料(表)。這能夠讓資料實現更好
的隔離與封裝。但即便是在這種情況下,也不要將表所在的方案名硬編碼到包
中。可以在包所在的方案中,為這些物件建立同義詞即可。這樣,就可以在
PL/SQL 程式碼中引用這些物件,而不用使用方案名(因為同義詞與程式碼在同一個
方案中),而這些同義詞會自動關聯到相應的物件上。如果物件名稱發生改變,
重新建立同義詞就行了。這些動作都可以很簡單地完成,也可以自動完成。
3. 公共同義詞與資料庫連結
對於上面提到的同義詞,顯然,我們討論的是私有同義詞。不要使用公共
同義詞。因為它們會覆蓋整個名稱空間中的私有同義詞。當一個應用程式建立
公共同義詞時,無法讓其繫結其他任何東西。這就是方案整合的一個限制:不
屬於特定方案的物件,容易與其他應用程式,或是其他版本、其他環境中的同
一應用的物件產生衝突。
4. 角色、表空間名稱與目錄
一個應用程式可以定義或引用其他物件,只要這些物件均處於資料庫的公
共名稱空間即可——例如角色、目錄以及表空間名稱。如果一個應用程式在不
同環境中執行,則這些環境其實也可以被整合到同一個資料庫中。只需要在執
行 DDL 指令碼時,為不同的環境分別設定不同的引數,從而可以讓這些資料庫
物件分別適用不同的環境即可。如果不是這種情況的話,那麼想實現方案整合
就有難度了。
另外一方面,這些不屬於特定方案的物件,也會讓資料移動的實現變得更
為複雜。例如,當想使用資料泵(Data Pump)來匯入一個方案時,這些物件可能
需要在事先就完成建立。
5. 遊標共享
即便一個應用程式是專門為方案整合而設計的,在將所有的東西都整合
到一個資料庫裡面時,也照樣可能會遇到效能方面的問題。我們曾經處理過
一個包含 3000 個方案的資料庫,它其實是一堆資料集市(data mart):結構相

同,資料不同。
另外,很顯然,應用程式的程式碼也都是相同的。使用者需要連線到其中一個
資料集市,然後執行查詢,而這些查詢已經在應用程式中進行了定義。這就意
味著同樣的查詢——甚至在 SQL 文字上也是完全相同的——將會執行在不同
的方案上。如果知道 Oracle 資料庫中的遊標共享是如何實現的,就立即能夠看
到問題所在:一個遊標會有上千個子遊標。一個父遊標會被所有的 SQL 文字共
享,當物件不同時,便會建立不同的子游標。當在多個方案中執行這些程式碼時,
問題就出來了。 SQL 解析時需要掃描一個相當長的子游標連結串列,而在掃描期間
需要持有 latch,這顯然會導致很嚴重的庫快取競爭。
在多租戶環境下,為滿足整合的目的,父遊標會被共享,但是在子游標搜
索方面需要進行一些效能方面的提升,從而緩解上述問題。
1.1.3 表整合
當想要對多個環境中的資料進行整合時,而這些環境又有著相同的應用程
序及程式碼版本,這就意味著要用到的表將會具有完全相同的結構,可以把所
有的東西都放到一張表中。通常情況下,我們是在每一個主鍵值中新增環境
ID(公司、國家、市場以及其他資訊)來區別資料。這樣做的好處,是可以一次
性管理所有的東西。例如,當想要新增索引時,可以為所有的環境新增。
基於效能和維護方面的原因考慮,可以基於環境 ID 來對錶中的資料進行
物理分割槽,並將不同的分割槽資料存放在不同的表空間中。但是,這樣做,其隔
離級別就會很低,並進而影響到效能、安全以及系統的可用性。
實際上,大部分應用程式都採用類似這樣的設計,並且一般都把資料儲存
在一個環境中。絕大部分情況下,新增到主鍵值前面的 ID 往往都只有一個值,
而這也是 Oracle 引入索引跳躍掃描的原因之一。可以使用虛擬私有資料庫策略
來管理對這些環境的訪問。可以使用分割槽交換技術,在物理上實現對這些分割槽
的獨立管理。如果想找一個類似的例子,可以看一下 RMAN 的資料庫(恢復目
錄):所有已註冊的資料庫,其資訊都儲存在相同的表中。但是,在儲存不同環
境(測試、開發以及生產環境)中的資料時,或是儲存不同版本(資料模型也不盡
相同)的資料時,這樣的隔離其實是不夠的。
1.1.4 伺服器整合
如果有多個獨立的資料庫,但是又不想為每個資料庫都配置一臺伺服器,那
麼可以將這些例項整合到一臺伺服器上。如果曾經登入過 Oracle 的 Ask Tom 網
站(astome.oracle.com/),並諮詢過在一臺伺服器上推薦配置幾個例項, Tom Kate
的答案是這樣的:“我們不建議在一臺主機上部署多個例項——主機可以是虛擬
機或物理機,我們並不關注——但是你可以這樣認為:一臺主機 = 一個例項。”

但是在真實生活中,就像我們看到的那樣,一臺資料庫伺服器上往往執行著多個
例項。可以在一臺主機上安裝多個版本的資料庫(ORACLE_HOME),也可以在一
臺主機上執行多個例項——並且很多時候都是不得不如此。我們曾經見過一臺
伺服器上執行著多達 70 個例項。
這種情況下,在例項之間進行隔離的方法就比較少了。比如記憶體,可以通
過設定 SGA_MAX_SIZE 引數來在物理上對記憶體進行分割。也可以在 Oracle
Database 12c 中使用 PGA_AGGREGATE_LIMIT 來限制程式使用的記憶體。可以
使用例項囚籠策略,來設定每個例項在 CPU 上執行的最大程式數量。在最新的
Oracle Database 12cR2 中,不需要企業版就可以使用例項囚籠策略。我們將在
第 3 章中討論這個主題。
但是,在一臺伺服器上執行大量的例項依然是個問題。例如,當要重啟服
務器時,需要啟動大量的程式,並完成記憶體分配。一次伺服器停機,無論是計
劃內的還是計劃外的,都會對大量應用程式造成影響,並且需要消耗大量資源
來處理多個 SGA 以及資料字典表。
1.1.5 虛擬化
現今,虛擬化是一個非常好的方法,可以在不需要管理大量物理伺服器的
前提下實現一個例項一臺伺服器。可以對環境進行極好的隔離設定,在限制範
圍內分配 CPU、記憶體以及 I/O 頻寬。甚至可以使用不同的網路來隔離這些資料
庫。但是,即便這些伺服器都是虛擬機器,也還是無法解決資源浪費,因為還
是要持有多個 OS、 Oracle 軟體、記憶體以及資料字典。並且,還是得管理多個數
據庫——備份恢復、實現高可用特性,比如 Data Guard 等。然後,還是有多個
OS 需要打補丁和監控。
此外,在虛擬化環境中,軟體許可也是夢魘般的存在。當進行軟體安裝
時, Oracle 軟體是按照處理器數量進行授權的, Oracle 會考慮這些因素,比
如與虛擬化技術相關的授權問題,以及在虛擬機器上安裝軟體並執行,等等。
當然,這些也依賴供應商所提供的管理程式,以及這些管理程式的版本。
1.1.6 一個例項管理多個資料庫
那麼問題來了,如何找到一種方法,能夠實現這樣的一種隔離級別:能夠
同時滿足環境的隔離與資源整合兩個目的。顯然,這種隔離級別高於方案隔離,
但是又低於我們現在所知道的例項與資料庫。也就是說,我們可以在一臺服務
器上,使用一個例項來管理多個資料庫。
在 12c 以前的 Oracle 資料庫版本中,顯然沒有這樣的功能。但是在現今
的多租戶架構中,這種方法就頗為可行了。現在,一個整合的資料庫可以管
理多個可插拔資料庫。另外,也出現了一種新的隔離級別,即獨立資料庫——

可插拔資料庫,這種架構在環境準備、移動以及系統升級等方面都提供了相
當高的敏捷性。
1.1.7 整合策略總結
表 1-1 簡要總結了在多租戶技術出現之前,幾種可選的整合策略之間的不
同之處。
表 1-1 不同整合策略的優劣分析

整合策略 優勢 劣勢
將所有內容當成一個整體來進行管理 隔離級別受限較大,且不適用於不
同環境
方案 可以實現例項、資料字典以及 HA 級
別的共享
公共物件之間容易出現衝突,且隔
離級別受限
資料庫 只需要管理一個資料庫 需要多個 SGA 及多組後臺程式,也
需要維護多個備份與 HA 配置
虛擬化 可以提供最佳的隔離級別,可以實現
職責分離,並提供 HA 以及 vMotion
方面的特性
授權許可問題,需要學習新的技術,
需要管理並執行多臺主機


1.2 系統字典與多租戶架構
在多租戶架構中,系統字典是變化最大的部分之一。讓我們來看看在以前
的版本中,系統字典是如何實現的,以及在 Oracle Database 12c 中,它又發生
了哪些變化。
1.2.1 過去:非 CDB
資料庫中既儲存資料,又儲存後設資料。例如,假設在 SCOTT 方案下有一
張表 EMP。該表的描述資訊——名稱、包含的列以及資料型別等——同樣也存
儲在資料庫中。這些描述資訊——也就是後設資料——儲存於系統表中,並且是
系統字典的一部分。
1. 字典
Codd 的規則(由 E.F.Codd 建立, 其提出了關係模型)定義了關係型資料庫中
的後設資料必須與資料有著同樣的表現形式:可以使用 SQL 來查詢後設資料或數
據。作為資料庫管理員,這樣的事情幾乎每天都在做。透過查詢字典檢視,例
如 DBA_TABLES,來獲取資料庫中物件的相關資訊。 Codd 的規則雖然只用於
表述邏輯層面,並由字典檢視提供這些資訊;但是 Oracle 走得更遠——透過在

關係型表中物理儲存這些後設資料資訊——對於同樣型別的表和應用程式表,這
些都為 SYS 方案所擁有,並儲存在系統表空間(SYSTEM 和 SYSAUX)中。
其實,在處理資料及後設資料資訊儲存時,並不需要使用 Oracle 字典的實際
名稱和詳細資訊,如圖 1-2 所示。表 SCOTT.DEPT 用於儲存使用者資料,該表的
定義則儲存在字典表中, 即 SYS.COLUMNS。該字典表用於儲存列的相關資訊,
並且由於這個字典本身也是表,因此它的定義資訊也採用同樣的方式儲存下來。

圖 1-2 資料及後設資料資訊儲存
當然,系統字典表中不僅僅儲存了表的定義資訊。一直到 8i 版本,資料存
儲(表的 extent 資訊)的物理描述資訊也都是儲存在字典表中的。但是,為了適
應可插拔的需求,表空間已經變得越來越自包含了。因此,資料儲存的處理方
式,隨著本地管理表空間的出現而發生了變化。另一方面,在每一個新的資料
庫版本中,都會有很多新的資訊會被新增到系統字典中。在當前的資料庫版本
中, Oracle 資料庫軟體的很大一部分功能,都是用 PL/SQL 包來實現的,而這
些內容,也是儲存在系統字典中的。
2. Oracle 管理的物件
對於 Oracle 資料庫而言, 其系統字典的實現方式, 就是我們前面所討論的:
字典儲存在資料庫中。每一個資料庫都有其自己的系統字典。並且當使用邏輯
匯入/匯出工具(EXP/IMP 或資料泵)來移動資料庫時,可能就會發現,有些字典
物件屬於系統,有些使用者物件屬於應用程式,而如何將這些物件區分開來,則

是一件很棘手的事情。當將一個資料庫完整地匯入(在 IMPDP 中使用 FULL=Y
選項, 這將在第 8 章進行討論)新建的資料庫中時, 你不會想把字典資訊也匯入,
因為在目標資料庫中,這些內容已經存在了。
當然, SYS 方案中的物件就是字典物件,並且它們會被資料泵忽略。但是
如果有人在 sys 下建立了使用者物件,那麼這些物件就會丟失,基於 sys 物件的
授權也會丟失。並且在其他地方也可以找到一些系統物件,例如在 OUTLN、
MDSYS 以及 XDB 等方案中。另外,系統中也有很多角色,也可以建立自己的
角色。想把它們區分開也不是那麼容易。
幸運的是, 在 12c 版本中, DBA_OBJECTS、 DBA_USERS 以及 DBA_ROLES
檢視中都包含了一個標記,用來指明哪些是資料庫維護的物件,是由資料庫建立
的,並且不屬於你的應用程式。我們可以在 12c 版本中查詢出這些 Oracle 維護的
方案列表:
SQL> select listagg(username,',' on overflow truncate with count) within
group(order by created) from dba_users where oracle_maintained='Y';
LISTAGG(USERNAME,','ONOVERFLOWTRUNCATEWITHCOUNT)
WITHINGROUP(ORDERBYCREATED)
---------------------------------------------------------------------
AUDSYS,SYS,SYSBACKUP,SYSDG,SYSKM,SYSRAC,SYSTEM,OUTLN,GSMADMIN_INTERNAL,
GSMUSER,DIP,XS$NULL,REMOTE_SCHEDULER_AGENT,DBSFWUSER,ORACLE_OCM,SYS$UMF,
DBSNMP,APPQOSSYS,GSMCATUSER,GGSYS,XDB,ANONYMOUS,WMSYS,OJVMSYS,CTXSYS,
MDSYS,ORDDATA,ORDPLUGINS,ORDSYS,SI_INFORMTN_SCHEMA,OLAPSYS,MDDATA,
SPATIAL_WFS_ADMIN_USR,SPATIAL_CSW_ADMIN_USR,LBACSYS,APEX_050000,
APEX_PUBLIC_USER,FLOWS_FILES,DVF,DVSYS
在 12c 版本中,這顯然是一個非常大的提升。可以很簡單地確認哪些方案
屬於你的應用程式,而哪些又屬於資料庫系統。 ORACLE_MAINTAINED 標記
列在 DBA_OBJECTS、 DBA_USERS 以及 DBA_ROLES 檢視中存在,因此現在
就可以很容易地區分哪些物件是由資料庫建立的,以及哪些物件是由應用程式
建立的。
注意:
12c 版本以前,也可以嘗試從不同的檢視中列出這些物件。當然,
這些檢視往往都由
Oracle 內部使用。如下是這些檢視的列表,它們可以用來進
行資料移動,並且是要必須忽略的:
EXP/IMP EXU8USR ,資料泵的
KU_NOEXP_TAB ,以及 Data Guard LOGSTDBY_SKIP_SUPPORT 。另外,
還有一個
DEFAULT_PWD$ 表,用於確定那些預先建立的方案。當然,還可以
查詢
V$SYSAUX_OCCUPANTS DBA_REGISTRY 檢視。
3. 系統後設資料與應用程式後設資料
我們已經描述瞭如下後設資料結構: 方案、 物件以及角色。 讓我們再深入一點,
深入資料去看一看。你已經知道表的定義資訊儲存在字典表中, 例如在圖 1-2 中,
我們簡要提了一下 SYS.COLUMN 表。但是,字典資料模型其實是很複雜的。
實際上,物件名稱儲存在 SYS.OBJ$中,表的資訊儲存在 SYS.TAB$中,列的
資訊則儲存在 SYS.COL$中,等等。這些都是表,並且每一個都有自己的定義
資訊——後設資料——儲存在字典表 SYS.TAB$中。例如,它裡面儲存了你自己
建立的表的資訊,但是也儲存了所有字典表的相關資訊。
在 SYS.TAB$中,有一行資料是用於儲存自身的定義資訊。你可能會問,
在建立表時(當然也是建立資料庫時),這一行是怎樣插入到表中的,因為當時
這張表應該還不存在。在 ORACLE_HOME 中,Oracle 有一段特殊的引導程式碼(關
於這部分內容,已經超出了本書的範圍。不過可以檢視 ORACLE_HOME/
rdbms/admin 目錄下的 dcore.bsq 檔案。也可以查詢 BOOTSTRAP$表,看看在啟
動階段,資料庫是如何在字典緩衝區中建立這些表的。此時這些基礎的後設資料
都是立即可用的,從而允許對餘下的後設資料進行訪問)。
所有的後設資料都儲存在這些表中,但是在非多租戶環境下有一個問題:系統
資訊(屬於資料庫的資訊)與使用者資訊(屬於應用程式的資訊)是混雜在一起的。這
些後設資料都儲存在同樣的表中,並且所有這些東西都儲存在同一個容器——數
據庫中。
這就是多租戶架構中與之前不同的地方:我們現在可以使用多個容器,從
而將系統資訊與應用程式資訊分離開來。
1.2.2 多租戶容器
在多租戶資料庫中,最重要的結構就是容器。一個容器包含資料和後設資料。
多租戶中的不同之處在於:一個容器可以包含多個容器,從而分離物件,無論
是物理上還是邏輯上。一個容器資料庫可以包含多個可插拔資料庫,以及一個
根容器,用來儲存公共物件。
多租戶資料庫是容器資料庫(Container DataBase, CDB)。在原有的架構中,
一個資料庫就是一個單一的容器,並且無法再分,這被稱為非 CDB。在 12c 版本
中,可以選擇是建立 CDB 還是非 CDB。可以建立一個 CDB,也就是多租戶資料
庫,透過在例項引數中設定 ENABLE_PLUGGABLE=true,並且在 CREATE
DATABASE語句中新增 ENBALE PLUGGABLE 選項來完成(更多細節請參閱第
2 章)。
這樣就會建立出一個 CDB, 其中可以包含其他容器。這些容器可使用數字、
容器 ID 或名稱進行標識。一個 CDB 中至少包含一個根容器和一個種子容器,
也可以新增自己的容器,在 12.1 版本中,最多可以新增 252 個容器;在 12.2

版本中,則可以多達上千個容器。
1. 可插拔資料庫
多租戶的目的是整合。相比於在一臺伺服器上部署多個資料庫,現在我們
只需要建立一個整合的資料庫即可,也就是 CDB。它裡面可以包含多個可插拔
資料庫(PDB)。並且每一個 PDB 對於它的使用者來說,都是一個完整的資料庫。
它有多個方案、公共物件,有系統表空間、字典檢視等。
多租戶架構可以用來在私有云或公有云上進行整合。可以實現數百個甚至
上千個 PDB 的整合。其目的是,可以提供多個 PDB 的快速就緒服務,但呈現
出來的狀態卻像是一個資料庫。根據這種設計方式,任意連線到一個 PDB 的用
戶都無法區分自己是連線到了一個 PDB 還是一個獨立的資料庫。
另外, 所有以前版本中使用的命令現在照樣可用。例如, 當連線到一個 PDB
時,可以執行 shutdown 來關閉這個 PDB。當然,它實際上並不會關閉例項。
因為該例項還管理著其他 PDB。但是對於使用者來說,他所看到的,與關閉一臺
獨立資料庫並無二致。
考慮另外一個例子。我們正連線到一個 PDB,並且我們沒有自己的 UNDO
表空間,因為該表空間是 CDB 級別的(在 12.2 版本中,我們可以改變這一點,
但是到第 8 章才能看到相關內容)。讓我們試著建立一個 UNDO 表空間:
SQL> show con_name
CON_NAME
------------------------------
PDB
SQL> create undo tablespace WHATEVER datafile '/nowhere' size 100T;
Tablespace created.
SQL> create undo tablespace WHATEVER datafile '/nowhere' size 100T;
Tablespace created.
SQL> create undo tablespace WHATEVER datafile '/nowhere' size 100T;
Tablespace created.
這裡並沒有報錯。但是 UNDO 表空間顯然沒有建立出來。畢竟,要建立一
個 100TB 的資料檔案是不可能的。我們所提交的語句只是被忽略了。其想法是,
既然在一個資料庫中提交的指令碼可以建立一個 UNDO 表空間, 那麼這樣的語法
在一個 PDB 中顯然也是應該被接受的。被接受的原因是,所有在非 CDB 中可
以做的事情,在 PDB 中必須也是可以進行的。但是它被忽略了,因為 UNDO
表空間是 CDB 級別的物件。
在多租戶環境中,也會有一些新的命令可用,並且你所知道的所有命令也
都被 PDB 所接受。可以為一個 PDB 使用者授予 DBA 角色,這樣該使用者就可以做
一個 DBA 能夠做的所有事情。並且該 PDB 使用者會被從其他 PDB 中隔離出來,
並將也將無法看到 CDB 級別的資訊。

2. CDB$ROOT
你的 SYSTEM 表空間有多大?在資料庫剛剛建立時,它差不就有幾個 GB
那麼大了。對於資料庫建立,我們這裡並不是指 CREATE DATABASE 語句,而
是指執行 catalog.sql 以及 catproc.sql(當然,在多租戶環境中,我們就不這樣稱呼
它們了,我們稱之為 catcdb.sql。實際執行的指令碼還是一樣)。一個空資料庫的字
典表,也將會佔用數 GB的空間,用來儲存字典結構以及系統包,它們都是 Oracle
軟體的一部分——ORACLE_HOME 下的二進位制檔案——但它們是以儲存過程
和包的形式部署在資料庫中的。如果在一臺伺服器上部署 50 個資料庫,那麼就有
50 個 SYSTEM 表空間並儲存同樣的內容(假設它們的版本和補丁號都一樣)。如果
想對數百個或數千個資料庫進行整合, 正如對 PDB 所做的那樣, 你可能不想對每
一個資料庫都儲存同樣的內容。可以將所有的公共資料只儲存在一個容器中,
並讓其他容器共享這些內容。這就是 CDB$ROOT:它是一個 CDB 中唯一的非
PDB 容器,用來儲存 PDB 之間的所有公共資訊。
基本上, CDB$ROOT 將會儲存所有的字典表、 字典檢視、 系統包(以 dbms_
開頭)以及系統使用者(SYS、 SYSTEM 等)——並且不再儲存其他內容。不要在
CDB$ROOT 中儲存使用者資料。如果需要,可以在所有的 PDB 中建立自己的用
戶。關於公共使用者,可以在第 6 章中瞭解更多資訊。
也可將 CDB$ROOT 視為 ORACLE_HOME 的擴充套件。它是資料庫軟體的一
部分,並儲存於資料庫中。它與 ORACLE_HOME 的版本相關,只要版本相同,
那麼所有 CDB 中的 CDB$ROOT 都是一樣的。 12.2.0.1 版本中的 CDB$ROOT
與你的資料庫基本也是一樣的。
3. PDB$SEED
多租戶資料庫 CDB 的目的是建立多個 PDB。不僅如此,還應該能夠根據
需要,簡單快速地建立 PDB。這也是 DBaaS(DataBase as a Service,資料庫即服
務)架構所關注的。如何透過 DBCA 來快速建立一個資料庫?可以透過一個包
含所有檔案的模板來建立資料庫。如果能夠克隆一個現成的空資料庫,那麼就
不再需要去重新建立所有的東西了(正如 catalog.sql 和 catproc.sql 所做的)。 這就
是 PDB$SEED: 它是一個空的 PDB, 可以對它進行克隆, 從而建立另外的 PDB。
不能對它進行修改,因為它是隻讀的,只能將它作為一個新 PDB 的源頭。
一個 CDB 最少包含一個 CDB$ROOT 容器和一個 PDB$SEED 容器。不能
對它們進行修改,只能使用它們。只有在對 CDB 進行升級或打補丁時,它們
的結構才會發生變化。
1.2.3 多租戶字典
多租戶架構的目的之一,就是將系統後設資料從應用程式後設資料中分離出來。

系統後設資料, PDB 之間所有的公共資訊,都儲存在 CDB$ROOT 中,稱為系統
物件。例如,包的定義,儲存在字典表 SOURCE$中,我們可以透過查詢
DBA_SOURCE 檢視來獲取這些內容。在一個非 CDB 中,該表則儲存了系統包
和你自己建立的包——有的包由 SYS 擁有,有的則由應用程式方案擁有;就讓
我們叫它 ERP 吧。在多租戶環境中, CDB$ROOT 只包含系統後設資料,因此在
前面的例子中,這也就意味著這些都是 SYS 包。
在我們指向應用程式的 PDB 中,我們稱其為 PDBERP, SOURCE$中將會
只包含我們應用程式的包,也就是 ERP 的包。讓我們看一個例子。我們使用
CDB$ROOT 並統計 SOURCE$中的行數。我們將其與 DBA_OBJECTS 進行關
聯,從而顯示出哪些是 Oracle 管理的物件(系統物件):
SQL> select o.oracle_maintained,count(*) from sys.source$ s join
dba_objects o on obj#=object_id
group by o.oracle_maintained;
ORACLE_MAINTAINED COUNT(*)
----------------------------- -------
Y 362030
SOURCE$中所有的行都是 Oracle 管理的物件,也就是系統包。
現在我們在 PDB 中看一眼:

ORACLE_MAINTAINED COUNT(*)
------------------------------ -------
N 8318
這裡的結果就不是系統包了,而是應用程式建立的包。當然,在你的環境
中,可能查詢結果會有所不同。但是這個例子,基本上已經顯示出了多租戶環
境下,字典資訊是如何分離的:在非 CDB 中,後設資料儲存於同樣的字典表中,
但是現在儲存到了不同的容器中,從而讓 Oracle 後設資料與應用程式後設資料分離
開來。注意,這與分割槽不同,對於字典表來說,它們倒更像是不同的資料庫。
1. 字典檢視
你知道我們為什麼查詢 SOURCE$而不是 DBA_SOURCE,假設它們能夠提
供同樣的結果嗎?檢查如下內容:
SQL> select o.oracle_maintained,count(*) from dba_source s join
dba_objects o on s.owner=o.owner and s.name=o.object_name and
s.type=o.object_type
group by o.oracle_maintained;


ORACLE_MAINTAINED COUNT(*)
----------------------------- ----------


Y 362030
在 CDB$ROOT 中,這與上面查詢得到的行數相同。但是在 PDB 中:
SQL> select o.oracle_maintained,count(*) from dba_source s join
dba_objects o on s.owner=o.owner and s.name=o.object_name and
s.type=o.object_type
group by o.oracle_maintained;
ORACLE_MAINTAINED COUNT(*)
------------------------------ ----------
Y 362030
N 8318
這裡,我們看到有更多的行數。實際上,我們是從 CDB$ROOT 中看到的
這些行。這裡有兩個原因。首先,我們說儲存在 CDB$ROOT 中的是公共資訊,
因此在 PDB 中顯然也能夠看到這些資訊。其次,我們說當一個使用者連線到一個
PDB 時,該使用者在一個獨立的資料庫中能看到什麼,在一個 PDB 中就也應該
能看到什麼。而在一個獨立的資料庫中,基於 DBA_SOURCE 的查詢應該顯示
所有的內容,包含系統的以及應用程式的。但是在查詢 SOURCE$時則不是這
樣。當然你也不希望這樣。只有檢視記錄下了這些資訊,並且你會期望去查詢
這些檢視。
PDB 中的字典檢視,提供了 PDB 的資訊,以及來自 CDB$ROOT 的資訊。
它不是分割槽,也不是一個資料庫連結。我們將在接下來的部分看看 Oracle 是如
何進行處理的。
當連線到 CDB$ROOT 時, DBA_SOURCE 檢視將會只顯示容器中的資訊。
但是新的以 CDB_開頭的檢視,則會顯示所有容器中的內容,你將在本節後面
1.2.4 節的“5. 容器中的字典檢視”部分看到這一點。
因此,從物理上來說,這些字典資訊是分離的。每一個容器都儲存各自用
戶物件的後設資料,根容器則儲存公共部分——主要是系統後設資料。從邏輯上來
說,從這些檢視中,我們可以看到所有的資訊,因為我們在非 CDB 中就可以
看到, PDB 顯然應該相容這一點。
2. 後設資料連結
Oracle 引入了一種新的方式,來將一個容器中的物件連結到其他容器:元
資料連結。每一個容器都擁有所有的字典物件(儲存在 OBJ$中並且可以透過
DBA_OBJECTS 訪問到),例如前面的例子中用到的系統包名稱。但是更多的對
象定義資訊(例如包的程式碼文字)並非儲存在所有的容器中,而是隻儲存在
CDB$ROOT 中。在 OBJ$中,每一個容器都有一個標識,這可以透過 DBA_
OBJECTS 中的 SHARING 列得到。當需要獲取某個物件的定義資訊時,該標誌

就會告訴 Oracle,這些資訊需要切換到 CDB$ROOT 容器去獲取。
如下是一些關於這些包中的某個包的資訊,所有的容器都包含相同的定義
資訊,查詢 CDB$ROOT 的 DBA_OBJECTS:
SQL> select owner,object_name,object_id,object_type,sharing,
oracle_maintained from dba_objects where object_name = 'DBMS_SYSTEM';
OWNER OBJECT_NAME OBJECT_ID OBJECT_TYPE SHARING ORACLE_MAINTAINED
----- ----------- --------- ----------- ------------- ---------------
SYS DBMS_SYSTEM 14087 PACKAGE METADATA LINK Y
SYS DBMS_SYSTEM 14088 PACKAGE BODY METADATA LINK Y
如下資訊則是從 PDB 中查詢得到:
SQL> select owner,object_name,object_id,object_type,sharing,
oracle_maintained from dba_objects where object_name = 'DBMS_SYSTEM';
OWNER OBJECT_NAME OBJECT_ID OBJECT_TYPE SHARING ORACLE_MAINTAINED
----- ----------- -------- ------------- ------------- -----------------
SYS DBMS_SYSTEM 14081 PACKAGE METADATA LINK Y
SYS DBMS_SYSTEM 14082 PACKAGE BODY METADATA LINK Y
可以看到,這些物件都具有相同的名稱和型別,並且都定義為 Oracle 管理的,
SHARING 列也都為 METADATA LINK。它們有不同的物件 ID。在對它們進行
連結時,只需要使用名稱和內部標籤。根據這些內容,我們就可以知道,這些
物件都是系統物件(Oracle 管理的),因此當我們在 PDB 中查詢這些物件時,
Oracle 就會知道需要切換到根容器來獲取它們的資訊。這就是後設資料連結的具
體處理行為。字典物件往往都比較大,因此只會儲存在 CDB$ROOT 中。但是
它們可以透過字典檢視,從而在任意位置都可以訪問到。
這與後設資料有關。對於應用程式而言,相關的後設資料則會儲存在對應的
PDB 中。 Oracle 管理的物件則儲存在 CDB$ROOT 中。後者是靜態資訊:它們
只有在對資料庫進行升級或打補丁時才會更新。可以看到,這樣做的好處,一
是可以降低資訊的重複程度,二是能夠加快 PDB 升級的速度,因為 PDB 中只
是一些連結罷了。
圖 1-3 顯示了字典資訊是如何分離的,當然也是對前面圖 1-2 的簡單擴充套件。
3. 資料連結(在版本 12.1中稱為物件連結)
當然,在字典中不僅僅只有後設資料。在 CDB 級別,多租戶資料庫也會存
儲一些資料。這裡是一個簡單的例子。假設 CDB 需要維護一個容器列表,並
將其儲存在系統表 CONTAINER$中然後可以透過字典檢視 DBA_PDBS 進行訪
問。這些資料可以更新,從而用來儲存容器的狀態資訊。但是,這些資料雖然

只在 CDB 級別才有意義,不過所有的 PDB 都可以訪問得到。下面我們就來看
看是如何共享這些資訊的。

圖 1-3 系統與使用者後設資料的分離
先查詢 CDB$ROOT:
SQL> select owner,object_name,object_id,object_type,sharing,
oracle_maintained from dba_objects where object_name in
('CONTAINER$','DBA_PDBS');
OWNER OBJECT_NAME OBJECT_ID OBJECT_TYPE SHARING ORACLE_MAINTAINED
----- ---- ------ --------- ----------- ------------ ---------------
SYS CONTAINER$ 161 TABLE METADATA LINK Y
SYS DBA_PDBS 4755 VIEW DATA LINK Y
PUBLIC DBA_PDBS 4756 SYNONYM METADATA LINK Y
然後查詢 PDB:
OWNER OBJECT_NAME OBJECT_ID OBJECT_TYPE SHARING ORACLE_MAINTAINED
----- ---------- --------- ---------- ------------- ----------------
SYS CONTAINER$ 161 TABLE METADATA LINK Y

第 1 章 多租戶概述 21
SYS DBA_PDBS 4753 VIEW DATA LINK Y
PUBLIC DBA_PDBS 4754 SYNONYM METADATA LINK Y
可以看到,訪問 CONTAINER$的檢視,實質上是一個資料連結。這就意味
著,當有會話來執行這些查詢時,其實資訊是從 CDB$ROOT 獲取到的。實際
上, CONTAINER$表在所有的容器中都存在,但是隻有在根容器中是真正儲存
資料的,其他都是空的。
1.2.4 使用容器
既然有了這麼多的 PDB,那麼如何使用它們?可以從識別它們開始。
1. 透過名稱和 ID 來識別容器
一個整合的 CDB 中,可以包含多個容器,它們可以透過名稱和數字,也
就是 CON_ID 來進行識別。在 12c 版本中,所有用來顯示一個例項中包含哪些
物件的 V$檢視,都額外新增了一列,用來顯示 CON_ID,以便標記物件屬於哪
一個容器。 CDB 本身就是一個容器,其容器 ID 為 CON_ID=0。被標記為
CON_ID=0 的物件,都是 CDB 級別的物件,並且不會關聯到其他容器。
例如,如下是我們在根容器中查詢 V$DATABASE 後得到的資訊:
SQL> select dbid,name,cdb,con_id,con_dbid from v$database;
DBID NAME CDB CON_ID CON_DBID
----------- -------- --- ----------- ---------
2013933390 CDB YES 0 2013933390
下面則是在 PDB 中執行查詢:
SQL> select dbid,name,cdb,con_id,con_dbid from v$database;
DBID NAME CDB CON_ID CON_DBID
--------- ---- --- --------- -------------
2013933390 CDB YES 0 2621919399
如果在不同的容器中執行上述查詢,結果可能也會有所不同。但是無論哪
種情況,所獲取到的資料庫資訊,都只是 CBD 級別的。該檢視中包含的資訊
來自於控制檔案,你將看到這些其實就是公共資訊,因此 CON_ID 被設定為 。
如果是非 CDB,那麼對於所有的物件而言, CON_ID 都為 。但是如果是在一
個多租戶架構中,那麼大部分物件都屬於特定容器。
任一 CDB 環境中,第一個容器都是根容器,名為 CDB$ROOT,並且
CON_ID=1。其他所有的容器都是 PDB。
任一 CDB 中的第一個 PDB,都是種子容器,名為 PDB$SEED。因為它是
CDB 中的第二個容器,所以 CON_ID=2。
CON_ID>2 的容器,就是使用者 PDB。在版本 12.1 中,可以建立額外的 252

22 第Ⅰ部分 多租戶意味著什麼
個 PDB。在版本 12.2 中,則為 4096 個 PDB。
2. 容器列表
字典檢視 DBA_PDBS列出了所有的 PDB(所有的容器,除了根容器)及其狀態:
SQL> select pdb_id, pdb_name, status,con_id from dba_pdbs;
PDB_ID PDB_NAME STATUS CON_ID
---------- ------------ --------------- ----------
2 PDB$SEED NORMAL 2
3 PDB1 NORMAL 3
4 PDB2 NEW 4
5 PDB3 UNUSABLE 5
6 PDB4 UNPLUGGED 6
對於 PDB 而言,當剛剛建立時,其狀態為 NEW,並且在第一次將其以讀/
寫方式開啟時,其狀態調整為 NORMAL,因為在第一次開啟 PDB 時,需要進
行一些相關操作。狀態為 UNUSABLE 表明該 PDB 建立失敗,並且唯一允許的
操作是將其刪除。狀態為 UNPLUGGED,則表明該 PDB 將會被傳輸到其他
CDB,而在源 CDB 上,唯一能做的操作,就是將該 PDB 刪除。
在版本 12.1 中,可以看到 NEW 這樣的狀態,此外還有其他一些狀態:NEED
UPGRADE,表明該 PDB 來源於其他版本的資料庫; CONVERTING,表明其
來自於一個非 CDB。當然,還有其他三種狀態: RELOCATING、 REFRESHING
以及 RELOCATED。我們將在第 9 章討論這些內容。
如下資訊是從資料庫字典中查到的。我們可以透過例項來列出容器的資訊,
這裡顯示了其開啟的狀態:
SQL> select con_id,name,open_mode,open_time from v$pdbs;
CON_ID NAME OPEN_MODE OPEN_TIME
---------- ----------- --------- --------------------------------
2 PDB$SEED READ ONLY 05-JAN-16 03.57.35.171 PM +01:00
3 PDB1 READ WRITE 05-JAN-16 04.49.27.558 PM +01:00
4 PDB2 MOUNTED
5 PDB3 MOUNTED
6 PDB4 MOUNTED
在非 CDB 中, MOUNTED 狀態表明當前控制檔案已經被讀取,但是資料
檔案還沒有被例項程式開啟。這裡查詢到的結果與之頗為類似:一個處於關閉
狀態的 PDB,其資料檔案為未開啟狀態。 PDB 沒有 NOMOUNT 狀態,因為控
制檔案是公用的。
要注意,無論是 SQL*Plus 還是 SQL Developer,都有一種快捷方式,可以

第 1 章 多租戶概述 23
用來顯示當前的 PDB。如果正處於根容器中,還可以顯示所有的 PDB:
SQL> show pdbs

CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ----------------- ---------------- ----------


2 PDB$SEED READ ONLY NO
3 PDB1 READ WRITE NO
4 PDB2 MOUNTED NO
5 PDB3 MOUNTED NO
6 PDB4 MOUNTED NO
3. 透過 CON_UID 和 DBID 來識別容器
可以看到,除了容器的名稱,還可以透過 ID 或 CDB 中的 CON_ID 來識別
容器。但是,當移動 PDB 時,其 CON_ID 將會發生變化。基於這個原因,還需要
一個唯一的識別符號 CON_UID。該號碼在 PDB 發生移動時也依然可以用來標識
PDB。 CDB$ROOT 是一個容器但不是 PDB,並且它也不會移動,因此其 CON_UID
為 1。
基於資料庫的相容性考慮,每個容器都有一個 DBID。 CDB 的 DBID 就是
CDB$ROOT, PDB 的 DBID 則為 CON_UID。
另外,每一個容器都還有一個 GUID:一個包含 16 個位元組的 RAW 值。它
在 PDB 建立時生成,並且永遠都不會再改變。當使用 OMF(Oracle Managed
Files, Oracle 管理的檔案)時, GUID 被用於目錄結構,並作為 PDB 的唯一標識
符。
所有這些識別符號都儲存於 V$CONTAINER 中,當然也可以使用這些函式來獲
取一個容器的 ID: CON_NAME_TO_ID、 CON_DBID_TO_ID、 CON_UID_TO_ID
以及 CON_GUID_TO_ID。如果容器不存在,就返回 null 值,如下是一些例子:
SQL> select CON_NAME_TO_ID('PDB$SEED'),CON_DBID_TO_ID(794366768),
CON_ NAME_TO_ID('XXX') from dual;
CON_NAME_TO_ID('PDB$SEED') CON_DBID_TO_ID(794366768) CON_NAME_TO_ID('XXX')
------------------------ ---------------------- --------------------
2 4
4. 連線到容器
前面我們對多租戶的分析, 是將其作為突破方案整合限制的一種方法來進行
討論的。那麼問題來了,如何在多個方案之間進行切換?而不是使用方案使用者進
行直接連線?這裡,可以使用 ALTER SESSION SET CURRENT_SCHEMA。
當然,也可以直接連線到一個 PDB,但是這部分內容我們將在第 5 章進行
討論。這些內容與服務有關,並且這是從使用者或應用程式連線到 PDB 的正確做

24 第Ⅰ部分 多租戶意味著什麼
法。但是現在,你已經連線到了 CDB,可以使用 ALTER SESSION SET
CONTAINER 命令,從而簡單地將會話切換到一個新的容器。
現在,我們已經連線到了 CDB$ROOT:
SQL> show con_id
CON_ID
------------------------------
1
SQL> show con_name
CON_NAME
------------------------------
CDB$ROOT
我們來改變一下當前容器:
SQL> alter session set container=PDB;
Session altered.
現在我們就在 PDB 中了:
SQL> show con_id
CON_ID
------------------------------
3
SQL> show con_name
CON_NAME
------------------------------
PDB
事務 如果在一個容器中開啟了一個事務,那麼將無法在其他容器中開啟
另外的事務。
SQL> alter session set container=PDB1;
Session altered.
SQL> insert into SCOTT.DEPT(deptno) values(50);
1 row created.
可以離開當前事務,並切換容器:
SQL> alter session set container=PDB2;
Session altered.
但是現在無法執行 DML 語句,因為它需要一個新的事務:
SQL> delete from SCOTT.EMP;
*
ERROR at line 1:

第 1 章 多租戶概述 25
ORA-65023: active transaction exists in container PDB1
首先,需要回到原來的容器並結束事務:
SQL> alter session set container=PDB1;
Session altered.
SQL> commit;
Commit complete.
然後可以在另外的容器中開啟一個新的事務:
SQL> alter session set container=PDB2;
Session altered.
SQL> insert into DEPT(deptno) values(50);
1 row created.
遊標 如果在一個容器中開啟了一個遊標,將無法在另一個容器中對該遊
標進行獲取操作。需要回到遊標所在的容器並進行獲取:
SQL> variable C1 refcursor;
SQL> exec open :C1 for select * from DEMO;
PL/SQL procedure successfully completed.
SQL> alter session set container=PDB2;
Session altered.
SQL> print C1
ERROR:
ORA-65108: invalid use of a cursor belonging to another container
基本上,從一個容器切換到另外一個容器往往是很容易的。但是在不同的
容器中進行的操作,則是相互隔離的,並且以前容器中的狀態是無法共享的。
例如,我們連線到 PDB1,設定 serveroutput 為 on,然後使用 dbms_output
命令:
SQL> alter session set container=PDB1;
Session altered.
SQL> set serveroutput on
SQL> exec
dbms_output.put_line('==>'||sys_context('userenv','con_name'));
==> PDB1
PL/SQL procedure successfully completed.
dbms_output 產生了輸出,可以看到 USERENV 顯示了當前的容器名稱。
現在我們切換到 PDB2:
SQL> alter session set container=PDB2;
Session altered.

26 第Ⅰ部分 多租戶意味著什麼
SQL> exec dbms_output.put_line('==> '||sys_context('userenv','con_name'));
PL/SQL procedure successfully completed.
這裡就沒有任何輸出結果了。 serveroutput 只是在 PDB1 中進行了設定,我
們需要在 PDB2 中也進行設定:
SQL> set serveroutput on
SQL> exec dbms_output.put_line('==> '||sys_context('userenv','con_name'));
==> PDB2
PL/SQL procedure successfully completed.
現在我們回到 PDB1:
SQL> alter session set container=PDB1;
Session altered.
SQL> exec dbms_output.put_line('==> '||sys_context('userenv','con_name'));
==> PDB1
PL/SQL procedure successfully completed.
這裡就不需要再次設定 serveroutput 了。當我們切換回來時,我們重新獲取
了原來 PDB 中的狀態。
使用 JDBC 或 OCI 我們的例子是在 SQL*Plus 中執行的,但是其他客戶
端就不能這麼做了。當使用一個在根容器中進行定義的使用者(公共使用者),並且
該使用者也被授予 PDB 的 SET CONTAINER 系統許可權時,就可以切換到這個
PDB。可以使用 JDBC(Java DataBase Connectivity )或 OCI(Oracle Call Interface)
來完成這個操作。例如,可以在應用伺服器上配置一個連線池,這樣在拿到連
接時,就可以將連線切換到所需的容器。當為資料庫多租戶建立公共應用服務
器時,這種方法是值得考慮的。
注意:
如果想使用版本 12.2 中關於容器的一些新特性,例如切換到一個使
用不同字符集的
PDB ,就需要使用版本 12.2 的客戶端軟體。不然就會收到
ORA-24964:ALTER SESSION SET CONTAINER 錯誤。
設定容器觸發器 基於某些理由,如果想在一個會話進行容器切換時執行某
些動作,例如設定不同的最佳化器引數,那麼可以建立 BEFORE SET CONTAINER
和 AFTER SET CONTAINER 觸發器。
如下是這些觸發器的工作機制:
● 在 PDB1 中建立 BEFORE SET CONTAINER 觸發器, 當處於 PDB1 中,
然後執行 ALTER SESSION SET CONTAINER 時就會觸發。如果觸發
器讀取到了容器的名稱,那就是 PDB1。
● 在 PDB2 中建立 AFTER SET CONTAINER 觸發器,當執行 ALTER
SESSION SET CONTAINER=PDB2 時就會觸發。

第 1 章 多租戶概述 27
這就意味著,如果在 PDB1 和 PDB2 中分別建立 before 和 after 觸發器,那
麼當從 PDB1 切換到 PDB2 時,這兩個觸發器都會分別觸發。
這是 PDB 中兩種不同的工作方式。也可以透過服務來連線到容器,我們將
在第 5 章討論這些內容。此時,在會話開始時,就可以使用 AFTER LOGON ON
PLUGGABLE DATABASE 觸發器執行某些程式碼。或者,也可以使用 SET
CONTAINER,然後使用 AFTER SET CONTAINER ON PLUGGABLE DATBASE
觸發器。當一個使用者在 PDB 中工作時,如果想對這些會話進行某些確定的設定,
那麼前面說的這兩項操作就都需要進行定義。要注意這裡的 PLUGGABLE 單詞
並不是必需的,因為這裡的語法與資料庫的行為是相容的。
5. 容器中的字典檢視
PDB中包含了所有你想從一個資料庫中看到的內容。這就意味著對一個PDB
中的字典檢視進行查詢,其結果應該與對一個資料庫進行查詢所返回的結果一
致。你同樣也擁有 DBA_/ALL_/USER_檢視,用來獲取 PDB 中物件的後設資料。
那些物件,要麼有許可權去訪問,要麼是你自己建立的。事實是,系統物件儲存在
什麼地方是透明的:可以在 DBA_OBJECTS 中看到系統物件,在 DBA_TABLES
中看到系統表,以及在 V$檢視中看到例項資訊。但是你所看到的行,都跟你當
前所在的 PDB 相關。
當處於 CDB$ROOT 中時,就可以看到 CDB_檢視。這些檢視就像是所有
開啟容器中 DBA_檢視的 UNION ALL 結果。 這是一個 CDB 資料庫管理員可以
使用的方法,從而檢視所有的物件。對於 CDB$ROOT 的使用者, V$檢視將會顯
示所有容器內的資訊。
最後,你可能想知道,你是在非 CDB 環境中還是在多租戶環境中。
V$DATABASE 中的 CDB 列為你提供了答案:
SQL> select name,cdb from v$database;
NAME CDB
---------- ---
CDB YES
1.3 什麼是 CDB 級別的整合
對於整合而言,實現共享資源的公共性是其主要目標。在例項與字典之上,
很多資料庫結構都是在 CDB 層面進行管理的。我們這裡並不討論資料檔案,
因為它們被指定到每一個容器上。並且它們之間唯一的共同之處就是必須擁有
相同的字符集(除了在將一個容器從另外一個 CDB 中傳輸過來時, 當然這一點我
們要到第 9 章才進行討論)。在一個容器資料庫中,其他型別的檔案都是公共的。

28 第Ⅰ部分 多租戶意味著什麼
SPFILE
對於所有容器而言,資料庫例項是公用的, SPFILE持有該例項的相關參
數,併為整個 CDB 進行屬性設定。 SPFILE 包含的設定,無法儲存在資料庫或控
制檔案中,因為這些設定必須在資料庫處於 mount 狀態之前就可用才行。
有些引數可以在 PDB 級別進行設定(在 V$PARAMETER 中,這些引數的
ISPDB_MODIFIABLE 列為 TRUE)。對這類引數的修改當然也可以持久儲存下
來。但是在修改這些引數時,即便在語法上設定 SCOPE=SPFILE,這些 PDB
級別的引數實際也會儲存在 CDB 的字典表(即 PDB_SPFILE$)中。它們不會存
儲在自身的 PDB 中,因為這些引數必須在開啟 PDB 之前就能夠訪問。在稍後
我們將會看到,當移動一個 PDB(插入/拔出)時,這些引數將會被抽取出來存放
到一個 XML 檔案中,並隨著 PDB 的資料檔案一起被傳輸。
控制檔案
控制檔案與資料庫中的所有其他結構都有關係。例如,控制檔案是唯一真
正儲存資料檔名稱的地方,在字典表中為 FILE_ID 列,只是對具體位置的引
用而已。在多租戶環境中,控制檔案位於 CDB 級別,並持有所有 PDB 的資料
檔案資訊。可以在第 9 章中看到這些與 PDB 相關的內容,即當一個 PDB 被拔
出/插入時,所有與該 PDB 相關的資料檔案資訊,也會被從控制檔案中匯出,
然後儲存到一個 XML 檔案中。
注意:
當我們提到“控制檔案”時,我們實際用的是複數形式 (control files)
因為可以,並且也應該對其進行多路複用以保護你的資料庫。這種基本的最佳
實踐,只需要照做就是,並不需要修改。並且從某種意義上說,在多租戶環境
中,資料庫的可用性尤為重要。因為一旦出現停機事件,那將會影響多個租戶。
當討論資料檔案時,有一個初始化引數可以用來控制一個例項可以開啟的
最大檔案數量。就是 DB_FILES,其預設值為 200。要注意,如果想建立數百
個 PDB,那麼很快就會達到這一限制。到時候就無法再建立新的表空間或 PDB
了,除非重啟例項。在多租戶環境中,重啟例項意味著會引起很多應用的停機
操作。因此應該避免這一點。故而,當打算在容器中管理多個 PDB 時,不要忘
記對 DB_FILES 引數進行正確設定。
UNDO
在版本 12.1 中,即第一個帶有多租戶架構的 Oracle 資料庫版本中, UNDO
表空間是公共的,並且處於 CDB 級別。但是在版本 12.2 中,我們有了新的選
項,可以在本地 UNDO 模式下執行 CDB。如果 LOCAL UNDO 被設定為 on,
則每一個 PDB 都擁有自身的 UNDO 表空間, 並且當所有會話往 PDB 的資料塊
中寫資料時,其 UNDO 資訊都會被儲存到該 PDB 本地的 UNDO 表空間中。只

第 1 章 多租戶概述 29
有在 CDB$ROOT 中執行的修改操作, 才會將 UNDO 資訊記錄到 root 的 UNDO
表空間中。
簡單點說,如果可能的話,將 CDB 執行在本地 UNDO 模式下比較好。UNDO
中包含了應用資料,並且如果我們將這些資料存放到公共的 UNDO 檔案中的
話,我們就無法實現 PDB 的隔離了。一個需要使用本地 UNDO 模式的原因,
就是當我們打算進行 PDB 的快速閃回或是基於時間點的恢復時。我們將在第 8
章解釋這些內容。
臨時表空間
臨時表空間可以在 CDB 或 PDB 級別建立。如果某個 PDB 中的使用者在執行
會話時沒有指定臨時表空間,並且該 PDB 也沒有預設的臨時表空間,該會話將
會使用 CDB 的臨時表空間。但這不是推薦的做法。我們可以為 root 的臨時表
空間設定限額(MAX_SHARED_TEMP_SIZE),從而控制 PDB 對它的使用。
當需要分配工作區,從而完成對物件連結檢視的遞迴查詢時, CDB$ROOT
的臨時表空間一般都由連線到根容器的會話使用, 或者由來自一個 PDB 的會話
使用。
當將一個臨時表空間設定為預設的臨時表空間時,如果是你建立了該
PDB,那麼你也可以指定其他的臨時表空間為預設的臨時表空間。但是在此之
後,你就無法將 CBD 的臨時表空間設定為該 PDB 的預設臨時表空間了。
重做日誌
重做日誌是用來保護例項的,因此,它們也是公共的。重做日誌的主要用
途,是對 buffer cache 中所有的修改進行記錄,並確保這些所有已提交事務的更
改能夠持久儲存下去。
多租戶環境下的 REDO 資料流與之前版本中的類似,除了在每一條 REDO
記錄中都要新增額外的資訊用來標記容器之外。並且對於恢復操作而言, REDO
資料的格式也極為關鍵,基於此, Oracle 很少去改變這些東西。
使用統一的 REDO 執行緒來處理所有的 PDB,對於 DBA 管理 CDB 而言,
也是頗有益處的。在非 CDB 環境中,當打算準備一個新的資料庫時,將會花
費很多時間和精力去設定恢復區大小、建立備份,以及建立並配置 Data Guard
物理備庫,如果使用了的話。但是在多租戶環境下,類似的工作,只需要做一
次就夠了,也就是 CDB。因為這就是與資料庫可用性相關的功能匯聚的地方:你
的備份、 Data Guard 以及 RAC 配置。可以簡單地建立一個新的 PDB,並從這個
已經配置好可用性的環境中受益:它會隨著 CDB 進行自動備份,自動在物理
備庫中建立(當然這裡需要使用 Active Data Guard), 以及能夠自動被所有 RAC
例項訪問。再強調一次,這就是因為用來實現資料庫可用性的關鍵架構——
REDO 資料流,都是在 CDB 級別進行運作的。

30 第Ⅰ部分 多租戶意味著什麼
但是,如果只使用一個 REDO 資料流,有時候也會導致效能問題。如果曾
經遇到過與日誌寫相關的效能問題,例如基於“log file sync”事件的長等待,
那麼就可以想象出,當 LGWR 程式需要進行所有 PDB 的 REDO 寫操作時,會
發生什麼事情。其結果就是,如果 LGWR 無法跟上 REDO 的生成速度,那麼
當使用者執行提交操作時,就不得不進入等待狀態。
因此,基於 LGWR 的可擴充套件性考慮, Oracle 在 12c 版本中引入了多執行緒
LGWR 結構。這裡, LGWR 是一個協調程式, 然後有多個從屬程式(LG00、 LG01
等)與之相關聯。這樣,例項的 REDO 資料流就可以採用並行方式進行資料寫
操作。當然, RAC 仍然是另一種實現 REDO 並行處理的方式。需要牢記在腦
海中的是,在多租戶環境中,調整 LGWR 以及 REDO 寫的數量是至關重要的。
當進行整合時,需要對存放 REDO 日誌的磁碟效能加以特別關注。
資料檔案
儲存在表空間資料塊中的資料檔案,屬於各自的容器,但它們也同樣為
CDB 所管理。對於 CDB 而言,這些資料檔案都有唯一的識別符號,也就是
FILE_ID:
SQL> select file_id,con_id,tablespace_name,relative_fno,file_name
from cdb_data_files order by 1;
FILE_ID CON_ID TABLESPACE_NAME RELATIVE_FNO FILE_NAME
------- ------ -------------- ----------- ---------------------------------
1 1 SYSTEM 1 /u02/oradata/CDB/system01.dbf
3 1 SYSAUX 3 /u02/oradata/CDB/sysaux01.dbf
5 1 UNDOTBS1 5 /u02/oradata/CDB/undotbs01.dbf
7 1 USERS 7 /u02/oradata/CDB/users01.dbf
8 3 SYSTEM 1 /u02/oradata/CDB/PDB1/system01.dbf
9 3 SYSAUX 4 /u02/oradata/CDB/PDB1/sysaux01.dbf
10 3 UNDOTBS1 6 /u02/oradata/CDB/PDB1/undotbs01.dbf
11 3 USERS 11 /u02/oradata/CDB/PDB1/users01.dbf
12 4 SYSTEM 1 /u02/oradata/CDB/PDB2/system01.dbf
13 4 SYSAUX 4 /u02/oradata/CDB/PDB2/sysaux01.dbf
14 4 UNDOTBS1 6 /u02/oradata/CDB/PDB2/undotbs01.dbf
15 4 USERS 11 /u02/oradata/CDB/PDB2/users01.dbf
relative file number,中文為相對檔案編號,是隨著可傳輸表空間被引入進
來的。因此在 12c 以前的版本中,這個特性已經存在相當一段時間了。多租戶
環境下,在 PDB 中,資料檔案是透過表空間編號和該檔案在表空間中的相對文
件編號(RELATIVE_FNO)進行標識的。此外,當進行檔案的移動、克隆或插入
到 PDB 中時,檔案編號的修改都不是必需的。只有絕對檔案編號(FILE_ID)會
被重新編號,從而確保其在 CDB 中的唯一性——但是在控制檔案和資料檔案

第 1 章 多租戶概述 31
頭中,這個重新編號的動作,是極其快速的。
CDB 級別的資料與後設資料
至此,我們已經解釋了與系統物件相關的字典,它們儲存在 CDB$ROOT
的 SYSTEM 和 SYSAUX 表空間中。它們是公共的,並且可以被 PDB 訪問。但
是除了這些基礎的資料庫物件(由 catalog.sql 和 catproc.sql 建立)外, 還有更多的
公共資訊也都儲存在根容器中。
1. APEX
預設情況下,一旦安裝了 APEX(在版本 12.2 中,可以選擇該元件),它就
處於 CDB 級別。 APEX 與系統字典類似,它們都用來儲存後設資料,並且不需要
安裝在 PDB$SEED 或其他 PDB 中。但是,這種方式有一個非常大的缺點:在
你的 CDB 中,只有一個 APEX 版本。並且當想在該 CDB 中插入一個執行 APEX
5.0 版本的非 CDB 時,將會遇到問題。例如,在 Oracle 雲服務中,當前的 CDB
上安裝的是 APEX 4.2 版本。
注意:
上面提到的這個問題,已經由 Mike Dietrich 在他的部落格 blogs.oracle.
com/UPGRADE/entry/apex_in_pdb_dose_not
上進行了詳細描述。 APEX 5.0 的官
方文件中也有如下描述:“
Oracle 推薦在根容器資料庫中移除 APEX ,從而滿足
大部分使用者的情況。除非所有的
PDB 都安裝並執行了 Oracle Application
Express(APEX)
,並且它們都具有完全相同的版本和補丁集。”
2. AWR
AWR(Automatic Workload Repository,自動工作量資料檔案庫)從例項的動
態檢視中收集大量的資訊(統計資訊、等待事件等)。在多租戶環境下,這些是
在 CDB 級別完成的。只有一個 job 用來收集所有容器的所有統計資訊,並儲存
在 CDB$ROOT 中。這就是物件連結檢視——AWR 檢視(以 DBA_HIST 開頭)
主要的應用案例。它們可以由每一個 PDB 進行查詢,但是讀取的資料實際上是
儲存在根容器中的。
因此,這裡有兩個重要的結論。其一,如果移動了一個 PDB,那麼 AWR
歷史資料將不會隨之移動;相反,它將仍然保留在原始的 CDB 中。可以使用
原來的資料庫讀取這些檢視,或者在他處將其匯出。但是儲存在 AWR 中的
CON_ID,應該是生成快照時的容器 ID,因此需要你去檢查 CON_DBID,從而
確認某一指定的 PDB。在每一個以 DBA_HIST 開頭的檢視中,實際上有三個
不同的識別符號:
● DBID是 CDB的 DBID,這與非 CDB環境中的一樣。該識別符號與 SNAP_ID
和 INSTANCE_NUMBER 一起,可以用來確定唯一的快照。

32 第Ⅰ部分 多租戶意味著什麼
● CON_ID 是容器 ID,是生成快照時所查詢的 V$檢視所在的容器 ID。
檢視中有些行可能不與任意容器相關聯,此時 CON_ID=0。其他行則
記錄了某個容器物件的統計資訊,因此在生成快照時,就記錄下了相
應的 CON_ID。
● CON_DBID 用來唯一標識一個 PDB,它和 DBID 用來唯一標識一個數
據庫一樣。
對於在 CDB 級別收集統計資訊的 AWR 而言,第二個結論是:當在 PDB
級別執行 AWR 報告時,它只會過濾出與你的容器相關的統計資訊,並且與查
詢 PDB 中 V$檢視得到的資訊一樣。但是你仍然需要知道,在同一份 AWR 報
告中,還是可以看到一些在 CDB 級別收集的統計資訊(這些行的 CON_ID=0)。
這就意味著,例如,可以在 AWR 的例項統計資訊部分,看到例項所完成的邏
輯讀的數量,但是在展示具體的細節(在 SQL 部分或段部分)時,只會顯示與你
的 PDB 相關的資訊。讓我們看一個例子。
在閱讀 AWR 報告的細節之前,我們通常會檢查一下大部分被捕獲的 SQL
語句,因為如果我們不打算去研究 SQL 語句的細節的話,這樣的動作就沒有必
要繼續了。如下是一份 AWR 報告中的 SQL ordered by Gets 部分:
SQL ordered by Gets DB/Inst: CDB/CDB Snaps: 139-143

-> Total Buffer Gets: 24,958,807
-> Captured SQL account for 88.9% of Total
這裡顯示捕獲了 89%的 SQL 語句,並且我們知道,當我們想去研究高邏輯
讀問題時,我們有了所需的細節。如果該比例比較低,那麼通常意味著我們生
成的報告,覆蓋了一個太大的時間視窗。因此大部分 SQL 語句在 end snapshot
之前都已經由於超時而被移出共享池了。但是,當在一個 PDB 上執行 AWR 報
告時,也可以看到另外一個原因:

SQL ordered by Gets DB/Inst: CDB/CDB Snaps: 139-143

-> Total Buffer Gets: 24,958,807
-> Captured SQL account for 21.6% of Total
這裡看不到任何區別,除了只捕獲了 21%的 SQL 語句。需要檢查 AWR 報
告的頭部,來看看它是否只覆蓋了一個 PDB。事實上我們有兩個 PDB 在此時
處於活動狀態,如下是另外一個 PDB:
SQL ordered by Gets DB/Inst: CDB/CDB Snaps: 139-143

-> Total Buffer Gets: 24,958,807
-> Captured SQL account for 60.3% of Total



第 1 章 多租戶概述 33
從一個 PDB 中,沒有辦法確認該 PDB 所有的 SQL 語句是否都已被捕獲。
對於該 PDB 而言,沒有類似總的邏輯讀這樣的統計資訊。
注意:
這是版本 12.1 中的行為,每個 PDB 的例項統計資訊可以在 V$CON_
SYSSTAT
中得到,但是不會被 ARW 收集。在版本 12.2 中,它們會被收集到
DBA_HIST_CON_SYSSTAT 中,並且也可以檢視相似的檢視:基於時間模型
(DBA_HIST_CON_SYS_TIME_MODEL) 和系統事件 (DBA_HIST_CON_ SYSTEM_
EVENT)
。在版本 12.2 中, AWR 報告會使用這些檢視,因此上述例子中的不一
致現象將不再出現。
statspack 如果沒有診斷包,那就無法使用 AWR,可以安裝 statspack。通
過查閱相關文件(spdoc.txt),可以知道 statspack 只能在 PDB 級別進行安裝。當
然,我們認為在 CDB 級別安裝也是有用處的,因為你會想去分析一下
CDB$ROOT 的活動情況。每一個想要收集快照的 PDB 都將儲存其自身的統計
資訊。因為現在統計資訊是在 PDB 級別被收集的,所以相關的行為就與 AWR
不同。我們在與前面例子中相同的時間點獲取 statspack 的快照,此時,從
spreport.sql 中讀到的資訊如下:當報告執行在 CDB$ROOT 上時,會話邏輯讀
的數值為 24 956 570;在其中一個 PDB 上執行時,數值為 5 709 168(22%);在
另外一個 PDB 上數值為 17 138 586(68%)。當在根容器上執行時, statspack 收
集與該 CDB 相關的統計資訊,而在 PDB 上執行時,則收集該容器的統計資訊。
1.4 本章小結
在前面長長的介紹中,我們已經解釋了在 2013 年, Oracle 為何要在版本
12c 中引入多租戶特性。我們已經看到了不同的整合選項,當然你也可能認為
並不需要在多租戶環境下執行應用。但是,這種新的架構將來會成為 Oracle 唯
一支援的資料庫架構,原有的非 CDB 架構正在被拋棄。因此,即便現在不想
在一個例項上執行多個 PDB,也得執行我們稱之為“單租戶”的資料庫(我們
將在第 3 章討論這一點),並且也不得不管理容器資料庫。
除了整合,新的架構也將應用資料與後設資料從系統字典中分離開來,從而
為資料移動和位置透明提供更強大的敏捷性。這些我們將在第 9 章進行探討。
下一章,將從建立一個整合資料庫開始。

購買地址:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26421423/viewspace-2217364/,如需轉載,請註明出處,否則將追究法律責任。

相關文章