1.1? 理解Oracle數(shù)據(jù)庫
1.2? Oracle高可用特性(High Availability)
1.3? 搭建高可用的周邊輔助環(huán)境
1.4? 高可用應(yīng)用設(shè)計
1.5? 高可用數(shù)據(jù)庫設(shè)計
1.6? 高可用性案例
1.7? 總結(jié)
引言
近幾年來,隨著IT技術(shù)的不斷進步,以及業(yè)務(wù)需求的不斷提高,搭建一個數(shù)據(jù)庫高可用環(huán)境已經(jīng)成為很多企業(yè)迫切的需求。本書從Oracle及Oracle周邊環(huán)境分析Oracle高可用環(huán)境的特性,為用戶搭建一個良好的Oracle高可用環(huán)境打下一定的理論基礎(chǔ)。
本章是本書的第1章,僅僅提供一些Oracle的基礎(chǔ)理論知識與高可用性構(gòu)架的思想,也希望能起到一個引導(dǎo)作用,為順利閱讀以后的章節(jié)打下一定的基礎(chǔ)。通過本章,希望能了解如下內(nèi)容:
●????? 理解Oracle的大致體系結(jié)構(gòu)
●????? 理解Oracle內(nèi)存結(jié)構(gòu)與后臺進程
●????? 理解Oracle物理與邏輯結(jié)構(gòu)
●????? 理解Oracle MAA最高可用性結(jié)構(gòu)與計劃
●????? 理解Oracle的典型高可用特性
u????????? Oracle并行服務(wù)器(OPS/RAC)
u????????? Oracle 數(shù)據(jù)保護(Standby/Data guard)
u????????? Oracle 數(shù)據(jù)復(fù)制(Advanced Replication/Streams)
u????????? Oracle主機上的HA
●????? 理解如何搭建一個高可用環(huán)境
u??????? 輔助環(huán)境的高可用設(shè)計
u??????? 應(yīng)用的高可用設(shè)計
u??????? 數(shù)據(jù)庫的高可用設(shè)計
●????? 理解一些典型的高可用設(shè)計的案例
1.1? 理解Oracle數(shù)據(jù)庫
1.1.1? Oracle數(shù)據(jù)庫體系結(jié)構(gòu)
Oracle是一個可移植的 數(shù)據(jù)庫——它在相關(guān)的平臺上都可以使用,即具有跨平臺特性,也正由于具有這個特性,加上Oracle優(yōu)越的性能與開放性,才使得Oracle能取得今天這 樣的成績。不過,在不同的操作系統(tǒng)上,Oracle除了內(nèi)核是完全一樣的以外,其他地方也略有差別,如在Linux/Unix上,Oracle是多個進程 實現(xiàn)的,每一個主要函數(shù)都是一個進程;而在Windows上,則是一個單一進程,但是在該進程中包含多個線程。
從其內(nèi)核,也就是內(nèi)部的整體 構(gòu)架上來看,Oracle在不同的平臺上是一樣的,如內(nèi)存結(jié)構(gòu)(Memory structure)、后臺進程(Background process)、物理與邏輯結(jié)構(gòu)(Physical&Logical structure)等等。所以,作為Oracle愛好者,或者是Oracle DBA,了解了Oracle的體系結(jié)構(gòu),就基本了解了Oracle的運行原理。
一般來說,Oracle把一 系列物理文件,如數(shù)據(jù)文件(Data file)、控制文件(Control file)、聯(lián)機日志(Redo log buffer)、參數(shù)文件(Spfile or pfile)等物理結(jié)構(gòu)及與之對應(yīng)的邏輯結(jié)構(gòu),如表空間(Tablespace)、段(Segment)、塊(Block)等組成的集合,稱為數(shù)據(jù)庫 (Database)。
與此對應(yīng),Oracle內(nèi)存 結(jié)構(gòu)和后臺進程被做成數(shù)據(jù)庫的實例(Instance),一個實例最多只能安裝(Mount)或打開(Open)在一個數(shù)據(jù)庫上,負(fù)責(zé)數(shù)據(jù)庫的相應(yīng)操作并 與用戶交互。一般情況下,一個數(shù)據(jù)庫對應(yīng)一個實例,但是在特定的情況下,如OPS/RAC的情況下,一個數(shù)據(jù)庫可以對應(yīng)到多個實例。
作為現(xiàn)在使用最廣泛的關(guān)系型 數(shù)據(jù)庫,Oracle到底有什么特性能讓它保持如此良好的運行狀態(tài)呢?除了Oracle的跨平臺特性與本身技術(shù)一直在發(fā)展之外,Oracle的體系構(gòu)架與 運行原理起到了不可忽視的作用,如Oracle的并發(fā)機制與鎖機制,從設(shè)計上就與其他數(shù)據(jù)庫有著本質(zhì)的區(qū)別,保證了讓Oracle比其他數(shù)據(jù)庫更適合于高 并發(fā)訪問的OLTP環(huán)境。
在Oracle版本不斷變更,新功能不斷添加,系統(tǒng)不斷完善的過程中,Oracle最基本的體系結(jié)構(gòu)卻是保持不變的,下面我們就先介紹一下Oracle的體系結(jié)構(gòu),從最基本的體系結(jié)構(gòu)上來理解Oracle。
1.1.2? Oracle實例(Instance)
Oracle內(nèi)存結(jié)構(gòu)
Oracle內(nèi)存結(jié)構(gòu)主要可以分共享內(nèi)存區(qū)與非共享內(nèi)存區(qū),共享內(nèi)存區(qū)主要由SGA(System Global Area)組成,非共享內(nèi)存區(qū)主要由PGA(Program Global Area)組成(見圖1-1)。
圖1-1? Oracle內(nèi)存結(jié)構(gòu)
從圖1-1中可以看到,Oracle共享內(nèi)存區(qū)主要包括數(shù)據(jù)緩沖區(qū)(Data buffer)、共享池(Shared pool)及一些其他的結(jié)構(gòu)。而PGA則主要包括會話的一些信息及排序區(qū),Hash join區(qū)域等,下面分別介紹這些內(nèi)容。
SGA
系統(tǒng)全局區(qū)(SGA,System Global Area)其實是一塊巨大的共享內(nèi)存區(qū)域,包含了Oracle的數(shù)據(jù)緩沖及眾多的控制結(jié)構(gòu)。這里的數(shù)據(jù)可以被Oracle的各個進程共用,如果有互斥的操 作,如鎖定一個內(nèi)存對象,則需要通過Latch與Enqueue來控制。
每個Oracle實例(instance)只能啟動一個SGA,除非通過RAC等一些特殊的全局管理方式,否則不同的實例只能訪問自己的SGA區(qū)域。通過如下的方式就可以查看SGA大小:
10gR2 ?Piner>show sga
Total System Global Area 8877225568 bytes
Fixed Size?????????????????? ?? 755296 bytes
Variable Size???????????? ?? 486539264 bytes
Database Buffers???????? ? 8388608000 bytes
Redo Buffers??????????????? ?? 1323008 bytes
以上結(jié)果是一個典型的OLTP環(huán)境中的SGA的分配情況,我們可以看到四個大的部分。
Fixed Size,包括了一些數(shù)據(jù)庫與實例的控制信息、狀態(tài)信息、字典信息等,啟動的時候就固定在SGA中,而且不會改變。
Variable Size,包含了shared pool、large pool、java pool、streams pool、游標(biāo)區(qū)和其他結(jié)構(gòu)等,合計450MB左右。
Database buffers,有時候也叫Data buffer,它是數(shù)據(jù)庫中數(shù)據(jù)塊緩沖的地方,數(shù)據(jù)塊在內(nèi)存中就緩存在這里。所以,在OLTP環(huán)境中,Data buffer是SGA中最大的緩沖區(qū),是數(shù)據(jù)庫性能高低的關(guān)鍵所在。
Redo buffers,它是為了加快日志寫進程的速度而設(shè)立的緩沖區(qū),在一般OLTP環(huán)境中,因為提交很頻繁,所以一般不會很大。
SGA的大小信息也可以從v$sga中獲得,與show sga的結(jié)果一樣。另外,v$sgastat記錄了SGA的一些統(tǒng)計信息,v$sga_dynamic_components則保存了SGA中可以動態(tài)調(diào)整的區(qū)域的一些動態(tài)或者手工調(diào)整記錄。
下面將介紹SGA中最重要的兩個對象,共享池(Shared pool)與數(shù)據(jù)緩沖區(qū)(Database buffer),其他的池,如Streams pool,在介紹Streams的章節(jié)時再另外介紹。
共享池(Shared pool)
共享池是SGA中非常關(guān)鍵的內(nèi)存片段,特別是在性能和可伸縮性上。由初始化參數(shù)shared_pool_size決定其大小,在Oracle 10g以后,Oracle可以自動管理大小。
在典型的OLTP高可用環(huán)境中,一個太小的共享池會扼殺性能,導(dǎo)致出現(xiàn)Ora-04031錯誤,使系統(tǒng)停止運行。但是太大的共享池也將消耗大量的CPU來管理。在數(shù)據(jù)倉庫環(huán)境中,因為并發(fā)進程的需要,可能會分配比較大的共享池。
提醒:在實際的高可用環(huán)境中,有很大的一部分故障就是因為共享池的原因而導(dǎo)致系統(tǒng)停頓甚至宕機的,如Latch爭用、Ora-0431錯誤、Library cache爭用與等待。
不正確地使用共享池只會帶來災(zāi)難性的后果,所以,必須先要了解 共享池的作用。共享池又可以分為SQL語句緩沖區(qū)(Library Cache)、數(shù)據(jù)字典緩沖區(qū)(Data Dictionary Cache)及一些控制結(jié)構(gòu)。而數(shù)據(jù)字典緩沖區(qū)與控制結(jié)構(gòu)是用戶無法直接控制的,所以,真正與用戶有關(guān)的其實就是SQL語句緩沖區(qū)。
當(dāng)一個用戶第一次提交一個SQL語句,Oracle會將這句SQL進行硬分析(Hard parse),這個過程類似于程序編譯,會耗費相對較多的時間,因為它要分析語句的語法與語義,獲得最佳的執(zhí)行計劃(Sql plan),并在內(nèi)存中分配一定的空間來保存該語句與對應(yīng)的執(zhí)行計劃等信息。
因為Oracle總是保存語句的執(zhí)行信息,當(dāng)數(shù)據(jù)庫第二次或者多次執(zhí)行該SQL時,Oracle自動跳過這個硬分析過程,變?yōu)檐浄治?#xff08;Soft parse)或快速軟分析(Fast soft parse),從而減少了系統(tǒng)分析的時間,減少CPU與Latch的消耗。
注意:Oracle中只有完全相同的語句,包括大小寫、空格、換行都要求一樣,才能重復(fù)使用以前的分析結(jié)果與執(zhí)行計劃。
圖1-2是一個完整的SQL語句的分析過程:
圖1-2? SQL語句的分析過程
所以,如果大量的,頻繁訪問的SQL語句都不采用綁定(Bind)變量,Oracle為了做SQL的硬分析,Shared pool latch將變得嚴(yán)重爭用與等待,同樣也會耗費大量的CPU,直到機器的資源耗盡。另外,因為Oracle會從共享池中分配空間來保存剛做完硬分析的 SQL語句,也將耗費大量的內(nèi)存空間,而且,這些被浪費的空間無法被重用。
對于編程者來說,要盡量提高語句的重用率,減少語句的分析時間,一個設(shè)計很差的應(yīng)用程序可以毀掉整個數(shù)據(jù)庫。為了避免出現(xiàn) 這樣的問題,Oracle從9i開始,還引進了一個新的參數(shù)cursor_sharing,不過,因為該參數(shù)總是帶來很多其他問題,如bug,所以,在現(xiàn) 有的數(shù)據(jù)庫版本上,還是不建議在高可用的生產(chǎn)環(huán)境中使用。
共享池采用LRU算法來決定共享池中的對象是否繼續(xù)保存,因為其空間畢竟有限,不可能無限保存所有的信息。所以,假設(shè)一個語句已經(jīng)被執(zhí)行過了,如果長時間沒有被使用,重新執(zhí)行的時候,也可能面臨重新分析,如果真的執(zhí)行次數(shù)如此之少,就不是高可用環(huán)境需要關(guān)心的了。
對于間歇性訪問的比較大的對象,如自定義的過程與包,如果不想在運行過程中被系統(tǒng)自動交換出去,可以調(diào)用DBMS_SHARED_POOL.KEEP存儲過程將該過程或包pin在共享池中,以減少重新載入的巨大代價。
我們可以通過如下命令手工清除共享池的內(nèi)容,除了有指導(dǎo)的特殊情況下外,該命令不建議在高可用的生產(chǎn)環(huán)境上運行。
SQL> alter system flush shared_pool;
與共享池相關(guān)的視圖很多,這里介紹幾個可能在高可用環(huán)境中經(jīng)常需要用到的視圖。
v$sqlarea,每條記錄都顯示了一個SQL語句的詳細(xì)統(tǒng)計信息,包括歷史以來的執(zhí)行次數(shù)、物理讀、邏輯讀、耗費時間等非常多的重要信息。
v$sqltext_with_newlines,因為 v$sqlarea只是記錄了一個語句或者是一個游標(biāo)的前1000個字符,如果是比較大的SQL語句,則不能在v$sqlarea中完全顯示。如果通過這 個視圖,可以獲得一個SQL語句的詳細(xì)信息。在這個視圖中,一個SQL語句分為多行保存,通過hash_value來標(biāo)示語句,通過piece來排序。
v$sql_plan視圖保存了被執(zhí)行的SQL語句的執(zhí)行計劃,可以通過特定的腳本獲得以前執(zhí)行過的語句的執(zhí)行計劃,在本書的后面章節(jié)有這樣的討論。不過,該視圖在9i的早些版本,如9206以前,存在一些bug,查詢該視圖,可能會出現(xiàn)600錯誤,甚至導(dǎo)致數(shù)據(jù)庫崩潰。
v$shared_pool_advice,這個視圖會對 Oracle的共享池做一些預(yù)測,范圍可能在當(dāng)前值的50%~200%之間,優(yōu)化者可以根據(jù)視圖顯示的信息做優(yōu)化判斷,如重新調(diào)整共享池大小。其中的字段 SHARED_POOL_SIZE_FACTOR說明了預(yù)測的共享池大小與現(xiàn)在大小的比例。
對于并發(fā)很多,而且訪問頻繁的高可用環(huán)境,需要避免如下的一些情況,在本書的后面將有詳細(xì)的案例分析來說明其原因與避免方法:
l?????????? 共享池不夠或bug導(dǎo)致的0431錯誤,該錯誤可能導(dǎo)致系統(tǒng)無法訪問。
l?????????? 分析數(shù)據(jù)改變導(dǎo)致執(zhí)行計劃改變,錯誤的執(zhí)行計劃可能導(dǎo)致系統(tǒng)無法運行。
l?????????? 增加了新的對象,如索引,引起執(zhí)行計劃改變而導(dǎo)致系統(tǒng)無法運行。
l?????????? 修改表導(dǎo)致依賴的存儲過程或者是包失效,而無法自動編譯成功,導(dǎo)致系統(tǒng)崩潰。
l?????????? 錯誤的操作方法導(dǎo)致嚴(yán)重的Latch爭用與等待。
數(shù)據(jù)緩沖區(qū)(Data buffer)
u????????? 數(shù)據(jù)緩沖區(qū)(Data buffer)
數(shù)據(jù)緩沖區(qū)(Data buffer)是Oracle中用于數(shù)據(jù)塊緩沖的區(qū)域,數(shù)據(jù)庫常規(guī)情況下讀寫(非直接讀寫)數(shù)據(jù)塊,Undo塊等,都會經(jīng)過這個緩沖區(qū),并適當(dāng)?shù)乇4嬖诰彌_區(qū)。如果下一次請求操作同樣的塊,則不需要從磁盤獲得,大大提高了系統(tǒng)的響應(yīng)速度。
數(shù)據(jù)緩沖區(qū)雖然不像共享池那樣容易導(dǎo)致系統(tǒng)故障,但是,它卻是影響OLTP系統(tǒng)性能的關(guān)鍵,因為它的Cache技術(shù)可以很 大程度地避免磁盤尋道,直接從Data buffer中獲得。所以,Oracle把從Data buffer獲得數(shù)據(jù)塊叫Cache hit,把從磁盤獲得數(shù)據(jù)塊叫Cache miss,它們的比率就是我們常說的Data buffer命中率。
在一個典型的OLTP的環(huán)境中,或者對事務(wù)型以及小查詢型的數(shù)據(jù)庫來說,更高的命中率意味著更快的響應(yīng)速度,所以命中率一 般要求在95%以上。大的Data buffer對提高系統(tǒng)的性能有巨大的好處,因為Data buffer比較大,緩沖的數(shù)據(jù)塊也就比較多,命中率也就更高。
但是在典型的OLAP環(huán)境中,大的Data buffer則不一定是必要的,因為OLAP的查詢基本是要求從磁盤返回,而且以直接讀寫居多,直接讀寫是不經(jīng)過數(shù)據(jù)緩沖區(qū)的,使得命中率失去意義。所以 在OLAP環(huán)境中,需要考慮用更多的磁盤驅(qū)動器,OLAP的速度取決于硬盤的多少與系統(tǒng)的帶寬。
數(shù)據(jù)緩沖區(qū)中的塊基本上在兩個不同的列表中管理。一個是塊的“臟”表(Dirty List),表示被用戶修改過的數(shù)據(jù)塊,采用檢查點隊列(checkpoint queue)來管理這些臟的數(shù)據(jù)塊,必要的時候通過數(shù)據(jù)庫寫進程(DBWR)來寫入這些臟塊;另外一個隊列是不臟的塊的列表(LRU List),比如通過Select從磁盤獲得的數(shù)據(jù)塊。一般的情況下,Oracle使用最近最少使用(Least Recently Used,LRU)算法來管理這些隊列,但是,從8i開始,另外還增加了Touch的概念,不僅僅是純粹的LRU算法。
塊緩沖區(qū)高速緩存又可以細(xì)分為以下三個部分Default pool、Keep pool、Recycle pool,在9i以前,它們對應(yīng)的是db_block_buffers、buffer_pool_keep、buffer_pool_recycle三個 參數(shù),分別表示每個緩沖區(qū)塊的個數(shù)。從9i開始,又重新引入了三個新的參數(shù):db_cache_size、db_keep_cache_ size、db_recycle_cache_size,分別表示該緩沖區(qū)的字節(jié)大小。
從9i開始,Oracle支持創(chuàng)建不同塊尺寸的表空間,這個新的特性同時也解決了在不同塊大小的數(shù)據(jù)庫之間傳輸表空間的問 題,并且可以為不同塊尺寸的數(shù)據(jù)塊指定不同大小的數(shù)據(jù)緩沖區(qū)。不同塊尺寸的數(shù)據(jù)緩沖區(qū)的大小就由相應(yīng)參數(shù)db_nk_cache_szie來指定,其中n 可以是2,4,8,16或32。如創(chuàng)建了一個大小為2K的非標(biāo)準(zhǔn)尺寸的表空間,就可以指定db_2k_cache_size為這個表空間指定緩存區(qū)的大 小。
注意:db_block_buffers與db_cache_size這兩種不同類型的參數(shù),不能同時設(shè)置。另外, db_nk_cache_size不能設(shè)置默認(rèn)標(biāo)準(zhǔn)塊大小的緩沖區(qū),如默認(rèn)塊大小為8K,則不能設(shè)置參數(shù)db_8k_cache_size。
正 確使用Default pool、Keep pool、Recycle pool也可以提高系統(tǒng)的性能,如把一個訪問很頻繁的表或索引放置在適當(dāng)大小的Keep pool中,可以減少物理讀,提升IO性能。是否決定使用這個功能,要看系統(tǒng)的具體情況,如參考Statspack中的Segment統(tǒng)計信息,關(guān)注其中 的物理讀部分,分析Top物理讀的對象,如果有些對象的確不大,但是物理讀又很大,就可以考慮緩沖分離。
視圖v$db_cache_advice與共享池的v$shared_pool_advice一樣,由Oracle自動根據(jù)一些數(shù)學(xué)模型算法,收集信息后產(chǎn)生的一系列建議值,可以作為調(diào)整Data buffer大小的參考。
u????????? v$bh與x$bh
v$bh在研究與查詢Data buffer使用上,是一個非常不錯的視圖,非常詳細(xì)地記錄了數(shù)據(jù)塊在數(shù)據(jù)緩沖區(qū)內(nèi)的使用情況,一條記錄對應(yīng)一個Block的詳細(xì)信息。
如果通過如下語句來查詢v$bh的來源,可以看到這個視圖來源于基表x$bh與x$le,但是,主要數(shù)據(jù)與字段都是來源于x$bh的。
SQL>select * from v$fixed_view_definition t where t.view_name='GV$BH'
不同的是,x$bh包含了更 多的信息,如touch count信息,在Oracle 8i以上作為LRU算法的一個重要的參考信息,表示了一個塊的熱點程度。touch count信息對應(yīng)到x$bh的tch字段,而段的data_object_id信息對應(yīng)到x$bh的obj,或者是v$bh的objd。有了這些基本信 息,其實就很好確認(rèn)熱點塊在哪里了。
下面簡單地介紹幾個關(guān)于這個視圖與基表的實用方法。
(1)對象有多少個數(shù)據(jù)塊緩沖在Data buffer中
為了詳細(xì)說明具體的情況,先創(chuàng)建一個測試表,并且插入一定的記錄進去。
Piner@10gR2>create table test(a int);
Table created.
Piner@10gR2>begin
2? for i in 1..5000 loop
3? insert into test values(i);
4? end loop;
5? end;
6? /
PL/SQL procedure successfully completed.
Piner@10gR2>commit;
Commit complete
如以上,先創(chuàng)建了一個叫test的表,并插入了5000條記錄,插入記錄后,用showspace存儲過程分析一下表的空間使用情況。關(guān)于這個存儲過程的具體代碼,在本書的附錄B中可以獲得,因為這個存儲過程本身很通用,這里就不多介紹這個存儲過程本身了。
Piner@10gR2>set serveroutput on
Piner@10gR2>exec show_space('TEST');
Total Blocks............................16
Total Bytes.............................131072
Unused Blocks...........................0
Unused Bytes............................0
Last Used Ext FileId....................4
Last Used Ext BlockId...................17
Last Used Block.........................8
PL/SQL procedure successfully completed.
可以看到的是,這張TEST的表一共使用了16個塊,數(shù)據(jù)文件id為4,我們再分析一下數(shù)據(jù)所在的Rowid。
Piner@10gR2>select f,b from (
2?? select dbms_rowid.rowid_relative_fno(rowid) f,
3 dbms_rowid.rowid_block_number(rowid) b
4?? from test) group by f,b;
F????????? ??B
---------- ----------
4???????? ??12
4???????? ??20
4???????? ??13
4???????? ??21
4???????? ??14
4???????? ??16
4???????? ??22
4???????? ??15
8 rows selected.
可以看到,數(shù)據(jù)塊其實只占用了8個塊,但是表合計占用了16個數(shù)據(jù)塊,另外8個塊是什么呢,它們是段頭,位圖塊等,是表中的額外開銷。至于這些塊的詳細(xì)信息,在本書的表空間與數(shù)據(jù)分布一章會有詳細(xì)介紹,現(xiàn)在只需要知道,該表有16個block,數(shù)據(jù)塊占了8個。
注意:以上通過Rowid查詢使用了哪些數(shù)據(jù)塊,只適合沒有發(fā)生行遷移與行鏈接的情況下,如新創(chuàng)建的表,插入的小記錄是適合的。如果發(fā)生了行遷移與行鏈接,因為Rowid本身不發(fā)生變化,而數(shù)據(jù)塊的使用卻會發(fā)生變化。
那么,現(xiàn)在分別查詢一下x$bh與v$bh,看看它們中間保存了幾條記錄。
Piner@10gR2>select file#,dbablk,tch from x$bh where obj=
2? (select data_object_id from dba_objects
3??? where owner='PINER' and object_name='TEST')
4? order by dbablk;
FILE#???? ?DBABLK??????? ?TCH
---------- ---------- ----------
4????????? ??9????????? ??2
4???????? ??10????????? ??2
4???????? ??11????????? ???5
4???????? ??12????????? ??2
4???????? ??13????????? ??2
4???????? ??14????????? ??2
4???????? ??15????????? ??2
4???????? ??16????????? ??2
4???????? ??17????????? ??2
4???????? ??18????????? ??2
4???????? ??19????????? ??2
4???????? ??20????????? ??2
4???????? ??21????????? ??2
4???????? ??22?? ?????????2
4???????? ??23????????? ??2
4???????? ??24????????? ??2
16 rows selected.
Piner@10gR2>select file#,block#,status from v$bh where objd=
2? (select data_object_id from dba_objects
3??? where owner='PINER' and object_name='TEST')
4? order by block#;
FILE#???? ?BLOCK# STATUS
---------- ---------- -------
4????????? ??9 xcur
4???????? ??10 xcur
4???????? ??11 xcur
4???????? ??12 xcur
4???????? ??13 xcur
4???????? ??14 xcur
4???????? ??15 xcur
4???????? ??16 xcur
4???????? ??17 xcur
4???????? ??18 xcur
4???????? ??19 xcur
4???????? ??20 xcur
4???????? ??21 xcur
4? ?????????22 xcur
4???????? ??23 xcur
4???????? ??24 xcur
16 rows selected.
可以看到,這兩個查詢都返回了16條記錄,從塊9到塊24,中間包含了數(shù)據(jù)塊所在的8個塊。至于為什么從塊9開始,在本書的后面也會有解釋,因為本地管理的數(shù)據(jù)文件頭部,有8個保留塊。
看x$bh,返回了塊的觸摸(touch count)信息,表示了一個塊的熱點程度,現(xiàn)在最熱的是數(shù)據(jù)塊11,它并不是數(shù)據(jù)塊,而是段頭,通過如下查詢也可以證明:
Piner@10gR2>select header_file,header_block from dba_segments
2? where owner='PINER' and segment_name='TEST';
HEADER_FILE HEADER_BLOCK
----------- ------------
4?????????? ??11
看v$bh,返回了塊的狀態(tài)信息,這里是xcur,表示排斥狀態(tài),被當(dāng)前instance獨占,也就是該塊正在被使用。常 見的狀態(tài)還有scur,表示被instance共享;cr,表示一致性讀;free表示空閑狀態(tài);read,表示正在從磁盤上讀取;write,表示正在 被寫入。至于v$bh的這些狀態(tài),也是從x$bh中通過decode函數(shù)根據(jù)字段state解釋過來的,所以能看得更明白一些。
如果這個時候,手工清除一次Data buffer,會發(fā)生什么情況呢?
Piner@10gR2>alter system flush buffer_cache;
System altered.
Piner@10gR2>select file#,dbablk,tch from x$bh where obj=
2? (select data_object_id from dba_objects
3??? where owner='PINER' and object_name='TEST')
4? order by dbablk;
FILE#???? ?DBABLK??????? ?TCH
---------- ---------- ----------
4????????? ??9????? ???? 0
4???????? ??10???????? ? 0
4???????? ??11????????? 0
4???????? ??12???????? ? 0
4???????? ??13????????? ? 0
4???????? ??14????????? ? 0
4???????? ??15???????? ? 0
4???????? ??16 ????????? 0
4???????? ??17??????? ?? 0
4???????? ??18??????? ?? 0
4???????? ??19???????? ? 0
4???????? ??20???????? ? 0
4???????? ??21???????? ? 0
4???????? ??22??????? ?? 0
4???????? ??23 ????????? 0
4???????? ??24??????? ?? 0
16 rows selected.
Piner@10gR2>select file#,block#,status from v$bh where objd=
2? (select data_object_id from dba_objects
3??? where owner='PINER' and object_name='TEST')
4? order by block#;
FILE#???? ?BLOCK# STATUS
---------- ---------- -------
4??????? ?????9 ????free
4???????? ??10 free
4???????? ??11 free
4???????? ??12 free
4???????? ??13 free
4???????? ??14 free
4???????? ??15 free
4???????? ??16 free
4???????? ??17 free
4???????? ??18 free
4???????? ??19 free
4???????? ??20 free
4???????? ??21 free
4???????? ??22 free
4??????? ???23 free
4???????? ??24 free
16 rows selected.
可以看到,x$bh中的塊的tch都恢復(fù)到0了,而v$bh中的狀態(tài)也都變成free了,但是記錄數(shù)并沒有發(fā)生變化,也就是說,數(shù)據(jù)塊雖然被刷到磁盤上去了,數(shù)據(jù)塊的記錄指針只不過是簡單地被清空而已。
明白了這些內(nèi)容,如果統(tǒng)計一個對象的非free狀態(tài)的v$bh的記錄數(shù),基本就反映了一個對象在Data buffer中的被Cache的塊數(shù)。如:
select count(*) from v$bh where objd=
(select data_object_id from dba_objects
where owner='PINER' and object_name='TEST')
and status !='free'
(2)熱點塊問題
剛才上面其實已經(jīng)就討論到了x$bh的touch count,這個數(shù)字將作為LRU算法的一個重要參考信息。如果一個塊被多次訪問,每次訪問都會導(dǎo)致該塊的記錄加一。
還是以上創(chuàng)建的測試表,這里重復(fù)選擇第一條記錄,看看對比情況。
Piner@10gR2>select data_object_id from dba_objects
2??? ?where owner='PINER' and object_name='TEST';
DATA_OBJECT_ID
--------------
11835
Piner@10gR2>select tch from x$bh
2???? where obj= 11835 and dbablk=12 and file#=4 and tch>0;
TCH
----------
5
下面采用了dbms_rowid.rowid_create函數(shù)來創(chuàng)建Rowid,表示新創(chuàng)建的Rowid類型為擴展Rowid,類型為1,data_object_id為11835,也就是上面的對象TEST,數(shù)據(jù)文件ID為4,塊的編號為12,行數(shù)為第一行。
Piner@10gR2> select count(*) from piner.test
2? ?where rowid = dbms_rowid.rowid_create(1,11835,4,12,0);
COUNT(*)
----------
1
Piner@10gR2>select tch from x$bh
2?? where obj= 11835 and dbablk=12 and file#=4 and tch>0;
TCH
----------
6
Piner@10gR2> select count(*) from piner.test
2? ?where rowid = dbms_rowid.rowid_create(1,11835,4,12,0);
COUNT(*)
----------
1
Piner@10gR2>select tch from x$bh
2?? where obj= 11835 and dbablk=12 and file#=4 and tch>0;
TCH
----------
7
從以上的例子可以看到,這里選擇的特定的一個數(shù)據(jù)塊,初始化的touch count值是5,經(jīng)過連續(xù)2次查詢以后,該值就變成7。根據(jù)這一變化,就可以基本判斷x$bh表中tch大的塊,一般都是熱點塊。
有了這點認(rèn)識,就可以根據(jù)x$bh來尋找系統(tǒng)中的熱點塊了。如通過如下語句來查詢top 10熱點塊所在的熱點對象。
select /*+ rule */ owner,object_name from dba_objects
where data_object_id in
(select obj from
(select obj from x$bh order by tch desc)
where rownum < 11) ;
注意:這里的hint提示是避免查詢字典表時,Oracle采用復(fù)雜的執(zhí)行計劃,反而更慢,在以后的例子里面也會經(jīng)常看到這樣的提示存在。
(3)一致性塊問題
上面演示了數(shù)據(jù)塊如果發(fā)生select,會導(dǎo)致touch count增加,由此可以判斷熱點塊。除了這個特性,x$bh還可以看到另外一個Data buffer中的特性,那就是塊的一致性讀。
在Data buffer中,默認(rèn)最多可以保存6個一致性塊的數(shù)據(jù)塊,也就是說,一個塊最多可以在x$bh中出現(xiàn)6行, 該特性由隱含參數(shù)_db_block_max_cr_dba決定。這個也就是我上面提到的,如果簡單統(tǒng)計有效的v$bh或者是x$bh的count(*) 數(shù)目,只能大致描述一個對象在Data buffer的數(shù)目。
還是用上面的例子表,選擇一直在測試的塊12來做實驗。
SQL> select tch, flag,
2? ? decode(bitand(flag,1), 0, 'N', 'Y') dirty,
3? ? decode(bitand(flag,16), 0, 'N', 'Y') temp,
4? ? decode(bitand(flag,1536), 0, 'N', 'Y') ping,
5? ? decode(bitand(flag,16384), 0, 'N', 'Y') stale,
6? ? decode(bitand(flag,65536), 0, 'N', 'Y') direct,
7? ? decode(bitand(flag,1048576), 0, 'N', 'Y') new
8 ???from? ???x$bh
9? ??where dbablk = 12
10??? and obj=11835
11??? and tch>0;
TCH?????? ?FLAG DIRTY TEMP PING STALE DIRECT NEW
---------- ---------- ----- ---- ---- ----- ------ ---
16???? ?524288 N???? ?N??? ?N??? ?N???? ?N????? ?N
這里可以看到該塊當(dāng)前的信息只有一行,表示只有一個一致性讀的塊存在,也就是當(dāng)前塊。但是,如果在別的會話中,反復(fù)修改該塊的記錄,或者刪除該塊的記錄。如:
會話1,刪除但不提交
SQL>delete from test where rowid = dbms_rowid.rowid_create(1,11835,4,12,0)
會話2,查詢該記錄
SQL>select * from test where rowid = dbms_rowid.rowid_create(1,11835,4,12,0)
馬上,就可以發(fā)現(xiàn),塊12在x$bh中增加了一行新的記錄,如果反復(fù)這么操作,則最多可以出現(xiàn)6個一致性塊。
SQL> select ??? tch, flag,
2? ? ??decode(bitand(flag,1), 0, 'N', 'Y') dirty,
3? ? ??decode(bitand(flag,16), 0, 'N', 'Y') temp,
4? ? ??decode(bitand(flag,1536), 0, 'N', 'Y') ping,
5? ? ??decode(bitand(flag,16384), 0, 'N', 'Y') stale,
6? ? ??decode(bitand(flag,65536), 0, 'N', 'Y') direct,
7? ? ??decode(bitand(flag,1048576), 0, 'N', 'Y') new
8? ????from ?? x$bh
9? ????where dbablk = 12
10?? ???and obj=11835
11??? ??and tch>0;
TCH?????? ?FLAG DIRTY TEMP PING STALE DIRECT NEW
---------- ---------- ----- ---- ---- ----- ------ ---
3?? ?35659777? Y???? ?N??? ?N??? ?N???? ?N????? ?N
2?? ?35659776 ?N???? ?N??? ?N??? ?N???? ?N????? ?N
2?? ?35659776 ?N???? ?N??? ?N??? ?N???? ?N????? ?N
1???? ??524416 ?N???? ?N??? ?N??? ?N???? ?N????? ?N
1???? ??524416 ?N???? ?N??? ?N??? ?N???? ?N????? ?N
1???? ??524416 ?N???? ?N??? ?N??? ?N???? ?N????? ?N
6 rows selected
可以看到,一個塊出現(xiàn)了6條記錄,而且,不管怎么樣修改,最多也就出現(xiàn)6條記錄,對應(yīng)了6個不同時間的一致性塊。如果再有SQL語句需要訪問這些一致性塊,只要其一致性塊存在,就不用重新構(gòu)建一致性塊了。
而且,上面第一行用灰度標(biāo)記出來的Y,表示dirty為Y,也就是表示這個最新的塊仍是臟數(shù)據(jù)塊,還沒有寫入數(shù)據(jù)文件中。
u????????? 數(shù)據(jù)緩沖區(qū)與讀打斷
在OLTP環(huán)境中,小的查詢語句,因為高緩沖區(qū)的命中率能取得良好的性能,是因為這些語句一般邏輯讀在100以下,所以才 能取得如此良好的效果。但是,如果要在一個典型的OLTP的環(huán)境中,做一個全表掃描,邏輯度與物理讀都非常大,但是因為有大量的斷續(xù)的數(shù)據(jù)塊在內(nèi)存中,而 導(dǎo)致一次性讀取的塊根本達不到參數(shù)db_file_multiblock_read_count指定的值,所以性能會更差。
提醒:如果在一個離散讀很典型的OLTP環(huán)境上做一個全表掃描,可能會因為有大量的塊已經(jīng)在內(nèi)存中而導(dǎo)致性能與沒有任何數(shù)據(jù)塊在內(nèi)存中的性能相差很遠。根據(jù)使用經(jīng)驗,這個時間消耗的差別可以達到5倍以上。
為什么會出現(xiàn)這樣的情況呢?假定一個表有100 000個數(shù)據(jù)塊,現(xiàn)在全部在硬盤中,參數(shù)db_file_multiblock_read_count為16,則全表掃描只需要發(fā)生100 000/16=6250個db file scattered read即可;但是,如果已經(jīng)有40 000個塊已經(jīng)緩沖在Data buffer中,但是分布很均勻,則可能需要發(fā)生幾萬次的db file sequential read + db file scattered read。看看圖1-3可能就更清楚了。
圖1-3? buffer與物理讀
可以簡單地認(rèn)為db file sequential read就是單塊讀,db file scattered read就是多塊讀,關(guān)于這兩個概念,在本書后面還有介紹。因為這里的sequential與scattered,不是說被讀取的表或者索引上的塊是連續(xù) 的還是分散的,而是指讀到內(nèi)存中的時候,是連續(xù)的還是分散的。
圖1-3用16個塊模擬了一個極端情況,假定db_file_multiblock_read_count=16,在情況1中,16個塊都在物理磁盤,那么只發(fā)生一個db file scattered read即可。但是,如果有一半的塊在內(nèi)存中,則可以分成兩種情況。
l?????????? 集中式緩存:比如上面的16個塊,前8個在緩存,那么這8個cache命中,另外8個發(fā)生一次db file scattered read即可,速度與全部讀效率差不多。
l?????????? 分散式緩存:比如上面的16個塊,很不幸的是,正好每隔一個塊,緩存一個塊,因為已經(jīng)在緩存中的數(shù)據(jù)不用讀,所以要發(fā)生8次db file sequential read讀,時間可能是一個db file scattered read的好幾倍。
具體論證這里就不詳述了,有興趣的讀者可以自己想辦法去證明。
SGA中的HASH算法
Hash算法是一種使用非常廣泛的算法,假定要把100個數(shù)字 放到10個容器中,最簡單的做法就是把這100個數(shù)劃分成10個范圍段,不同的范圍段放到不同的桶中即可。Hash算法采用了類似的方法,可以把一個復(fù)雜 的結(jié)構(gòu)Hash成一個簡單的數(shù)字,然后,根據(jù)數(shù)字的比較就可以找到對應(yīng)的目標(biāo)(見圖1-4)。
因為主機的內(nèi)存越來越大,共享池與數(shù)據(jù)緩沖區(qū)也越來越大,在高達幾十個GB甚至幾百個GB的SGA時,如果沒有一個合理的快速的管理方法,而是遍歷所有的內(nèi)存區(qū)域肯定是不現(xiàn)實的做法。
共享池使用的Hash算法,這個可能更好理解一些,因為從數(shù)據(jù)庫中也可以看到,每個SQL語句都有hash value,如果是一個新的SQL語句,在進入共享池之前,要先計算hash value,然后,根據(jù)hash value去對應(yīng)的桶(buckets)中查找是否有相同的SQL語句存在。這也就是為什么一定要SQL語句完全相同才能重用的原因,因為稍有差異,包括 大小寫不一樣,計算出來的hash value就不一樣。
圖1-4? SQL Hash算法
除了共享池,數(shù)據(jù)緩沖區(qū)也使用Hash算法,至于數(shù)據(jù)緩沖區(qū)中的Block bucket的個數(shù)則由隱含參數(shù)_db_block_hash_buckets決定。一個塊應(yīng)當(dāng)放到哪個Buckets里面,則是由Block的文件編 號、塊號等做Hash 算法決定的,Bucket里面存放了這些Buffers的地址。這樣的話,只需要根據(jù)塊的信息,計算出一個Hash值,就能很快地訪問到這個數(shù)據(jù)塊了。
PGA
Program Global Area(PGA)用來保存與用戶進程相關(guān)的內(nèi)存段,PGA總是由進程或線程在本地分配,在Oracle 9i以前,它們完全私有,其他進程與線程無法訪問。另外,User Global Area(UGA)實際上是會話的狀態(tài),它是會話必須始終能夠得到的內(nèi)存。對于專用服務(wù)器進程,UGA在PGA中分配。對于共享服務(wù)器(有時候也叫多線程 服務(wù)器,MTS),UGA在Large pool中分配。PGA/UGA一般保存了用戶的變量、權(quán)限、堆棧、排序(Sort)空間、Hash jion空間等信息。
在Oracle 9i以前的版本中,我們可以通過手工修改sort_area_size、hash_area_size等值控制PGA的使用率。使用這種分配方法存在一個 弊端,因為數(shù)據(jù)庫中,特別是大并發(fā)的OLTP高可用數(shù)據(jù)庫上,一般活躍著幾千個并發(fā)進程,它們都有私有信息,SQL信息,排序或者Join區(qū)域,所以不恰 當(dāng)?shù)脑O(shè)置,可能導(dǎo)致用戶空間消耗太大,而且因為進程之間私有而不能共享,導(dǎo)致大量內(nèi)存的消耗而嚴(yán)重影響主機的性能。
從Oracle 9i起,開始使用PGA自動管理,用pga_aggregate_target參數(shù)來指定所有session一共使用最大PGA內(nèi)存的上限。這個參數(shù)可以 被動態(tài)地更改,賦值范圍從10M~(4096G-1) Bytes。另外,9i里還提供了workarea_size_policy參數(shù)用于開關(guān)PGA內(nèi)存自動管理功能:自動管理(AUTO)或者手工管理 (MANUAL)。在手工管理模式下或多線程服務(wù)器模式下,還是跟8i一樣手工修改sort_area_size、hash_area_size等值控制 PGA的使用率。
Oracle 10g之前,pga_aggregate_target只在專用服務(wù)模式下生效。而10g以后,PGA內(nèi)存自動管理在專有服務(wù)模式(Dedicated Server)和MTS下都有效。在自動PGA管理模式下,有一套非常復(fù)雜的管理機制,要描述清楚該管理機制對于本書來說并不重要,在高可用的OLTP環(huán) 境中,自動PGA的管理只要設(shè)置到一定的值,如2G左右,就一般能滿足系統(tǒng)的需求,而不會影響系統(tǒng)的性能。而在OLAP環(huán)境,因為需要大量的join空 間,理解PGA的自動管理機制還是很重要的,這里就簡單介紹一下。
首先,我們把Oracle用于排序,join的內(nèi)存空間叫工作區(qū)域(workarea),把能進行完全內(nèi)存操作的 workarea大小叫做最佳大小optimal size。與之對應(yīng)的還有onepass,使用最小寫磁盤操作,大部分在內(nèi)存中進行。multipass,表示將會發(fā)生大量磁盤操作,性能會急劇下降(見 圖1-5)。
圖1-5? PGA與sort、jion
在一個高可用的OLTP環(huán)境中,要保證99%以上的排序與join操作都是在最佳大小 optimal(cache)size下完成的。要保證沒有這樣的操作在multipass環(huán)境下完成。當(dāng)一個語句從用戶進程提交運行時,Oracle會 運行一套復(fù)雜的機制來決定需要用多大的內(nèi)存,假定這個需要的內(nèi)存大小稱為expected size,在Oracle 9i中,可以參考如下幾個規(guī)則。
規(guī)則1:expected size 不能小于minimum memory 需求。
規(guī)則2:expected size 不能大于optimal memory 需求。
規(guī)則3:如果bound介于minimum和optimal之間,那么將會使用bound值作為expect size。
sort操作除外,因為sort操作并不會從多余內(nèi)存中得到利益,上面也已經(jīng)提到,所以當(dāng)sort操作時將會取onepass作為expect size。
規(guī)則4:如果這個workarea是并行執(zhí)行的,那么它的expect size和它的并行度成正比。
規(guī)則5:最后,expect size不能超過pga_aggregate_target大小的5%或100MB,并行操作下不能超過pga_aggregate_target大小的30%。
在Oracle 10g R2以后,expect size不能超過100MB這個條件已經(jīng)放寬了,不再是固定的值,而是取決于一個內(nèi)部參數(shù)_pga_max_size,可使用值為該參數(shù)值的一半,并另外 取決于系統(tǒng)設(shè)置的pga_aggregate_target參數(shù)的大小,在一定值以后,基本是該值的10%左右。
v$pgastat顯示了詳細(xì)的PGA的統(tǒng)計信息,該視圖可以顯示從instance以來的PGA的詳細(xì)使用信息,包括PGA大小是否足夠。
v$pga_target_advice是PGA的一個預(yù)測統(tǒng)計信息,Oracle會模擬不同PGA大小情況下的性能數(shù)據(jù),為DBA調(diào)整PGA大小做一定的參考。
自動內(nèi)存管理
Oracle的一個重要發(fā)展方向就是自動管理,當(dāng)然,SGA與內(nèi)存也 不例外。從Oracle 9i開始,就出現(xiàn)了一個新的參數(shù)sga_max_size,可以保證在此數(shù)值之內(nèi)的內(nèi)存可以自由地修改與調(diào)配。如指定了sga_max_size,就可以 在這個范圍內(nèi)自由地設(shè)置Shared pool、Data buffer等的大小。
sga_max_size的參數(shù)設(shè)置的內(nèi)存大小,在instance啟動的時候就分配完成,并且不可以動態(tài)修改。所以,在系統(tǒng)啟動之前,需要規(guī)劃好這個參數(shù)。如果不特別指定該參數(shù)大小,該參數(shù)大小就默認(rèn)等于所有SGA大小之和。
從Oracle 10g開始,又出現(xiàn)了另外一個新的參數(shù),sga_target,只要設(shè)置了這個參數(shù),所有的SGA的組件,如Shared pool、Data buffer、Large pool等,都不需要手工指定了,Oracle會自動管理。這一特性被稱為自動共享內(nèi)存管理(Automatic Shared Memory Management,ASMM),也就是說,Oracle會根據(jù)需要隨時改變各個內(nèi)存組件的大小,以達到最佳使用狀態(tài)。
當(dāng)然,如果在自動管理模式下,sga_target的大小不能超過參 數(shù)sga_max_size的大小值。因為sga_max_size指定的是SGA的最大值,而sga_target指定的是SGA現(xiàn)在的 值,sga_target在sga_max_size的大小范圍內(nèi)可以動態(tài)修改。自動SGA管理模式下,也支持手工修改各個內(nèi)存組件的大小,如把 Shared pool指定一個確定的值,也是可以的。另外,如果設(shè)置sga_target=0,則是自動關(guān)閉自動共享內(nèi)存管理功能。
SQL> alter system set sga_target = 2000M;
SQL> alter system set shared_pool = 200M;
SQL> alter system set db_cahe_size = 1000M; ?
SQL> alter system set sga_target = 0;? --關(guān)閉ASMM
從Oracle 11g以后,這個自動化管理的范圍進一步擴大,從SGA擴展到整個Oracle內(nèi)存,包括SGA+PGA,所以這個特性被改稱為自動內(nèi)存管理(Automatic Memory Management,AMM)。
與SGA自動管理相對應(yīng),重新引入兩個新的參數(shù),那就是memory_max_target與memory_target。作為DBA或者管理員,設(shè)置好memory_max_target與memory_target之后,就不用關(guān)心SGA與PGA的大小了。
與sga_max_size對應(yīng),memory_max_target不能被動態(tài)修改,需要在系統(tǒng)啟動的時候規(guī)劃好。同樣,與sga_target相對應(yīng),memory_target可以在memory_max_target大小范圍內(nèi)動態(tài)修改,但是不能突破它的范圍。
當(dāng)然,如果指定了memory_target,還想手動修改SGA大小與PGA大小,也可以手動修改這些參數(shù)。另外,如果指定memory_target=0,則關(guān)閉內(nèi)存自動管理,采用手工分配策略。
SQL>alter system set memory_target= 3000M;
SQL>alter system set sga_target = 2000M;
SQL>alter system set pga_aggregate_target = 1000M;
SQL>alter system set memory_target = 0;? --關(guān)閉AMM
在自動管理模式下,可以減少管理成本,讓DBA把時間與精力投入到其他更重要的工作中去。另外,作為DBA,也必須規(guī)劃好數(shù)據(jù)庫的SGA大小和PGA大小,如果是Oracle 11g,則只用規(guī)劃好總體內(nèi)存大小。
不過,由于操作系統(tǒng)尋址能力有限制,不通過特殊設(shè)置,在32位的系統(tǒng)上SGA最大也只能達到1.7GB,通過特殊設(shè)置,可以達到3GB或者更大。在64位的系統(tǒng)上已經(jīng)沒有這個限制,SGA可以達到幾十GB甚至幾百GB。
作為SGA+PGA或者是memory_max_target,如果在內(nèi)存比較小的時候,如1GB的總內(nèi)存,可以考慮給40%~50%;在4G~8G的時候,可以考慮給50%~60%;在更大的內(nèi)存情況下,一般可以考慮給70%,而且最好不要超過70%。
單獨作為PGA,則在不 同的應(yīng)用環(huán)境上可能有一些差異,如OLTP環(huán)境中,對PGA的大小要求并不高,可能1~2GB的PGA內(nèi)存大小就可以滿足需求,而在OLAP或者是DSS 環(huán)境中,SGA的Data buffer對系統(tǒng)的影響不大,而PGA因為Sort、并行與Hash jion的需要,可以適當(dāng)?shù)脑O(shè)置到總內(nèi)存的40%~50%。
注意:有的操作系統(tǒng)上,如Aix 5.3上,Oracle SGA默認(rèn)不要超過70%,否則,可能會導(dǎo)致系統(tǒng)故障甚至系統(tǒng)宕機。
1.1.3? 后臺進程(Background process)
后臺進程就是與用戶無關(guān),Oracle自動運行的守護進程,用來管理數(shù)據(jù)庫的讀寫、恢復(fù)和監(jiān)視等工作。而用戶進程 (User process)是當(dāng)一用戶運行一應(yīng)用程序時,如PRO*C程序或一個Oracle工具(如SQL*PLUS),為用戶運行的應(yīng)用建立一個用戶進程,與用 戶進程相對應(yīng),Oracle會生成很多服務(wù)進程(Server Process)。
可以通過如下命令查詢到一個Linux/Unix下的Oracle 9i系統(tǒng)后臺進程:
piner@Oracle$ps -ef|grep ora_|grep -v grep
oracle? 303146?????? ??1?? 4?? ?Aug 31????? - 4631:08 ora_lgwr_test
oracle? 475148?????? ??1?? 9?? ?Aug 31????? - 2046:32 ora_dbw0_test
oracle? 483402?????? ??1?? 0?? ?Aug 31????? - 258:41 ora_arc0_test
oracle? 585780?????? ??1?? 0?? ?Aug 31????? - 74:17 ora_smon_test
oracle? 594042?????? ??1?? 0?? ?Aug 31????? - 257:08 ora_arc1_test
oracle? 622800?????? ??1?? 0?? ?Aug 31????? - 26:19 ora_cjq0_test
oracle? 729262?????? ??1?? 0 ???Aug 31????? - 94:24 ora_pmon_test
oracle? 778476?????? ??1?? 0?? ?Aug 31????? -? 0:06 ora_reco_test
oracle? 831612?????? ??1?? 0?? ?Aug 31????? - 236:34 ora_ckpt_test
但是,如果在Windows機器上,Oracle后臺進程相對于操作系統(tǒng)線程,打開任務(wù)管理器,我們只能看到一個ORACLE.EXE的進程,但是通過另外的工具,就可以看到包含在這個進程中的線程。后臺進程與其他結(jié)構(gòu)的關(guān)系如圖1-6所示:
圖1-6? 后臺進程
圖1-6只列出了一些最基本的后臺進程,也就是能保證Oracle數(shù)據(jù)庫運行的最基本的幾個后臺進程。雖然在經(jīng)過Oracle 9i/10g/11g的不斷發(fā)展后,后臺進程也越來越多,并且越來越復(fù)雜,不過這幾個基本的后臺進程基本一直沒有什么變化。
另外,上圖還列出了專用服務(wù)器與共享服務(wù)器的差別,在專用(dedicated)模式下,一個用戶進程會對應(yīng)一個服務(wù)進程。在共享服務(wù)器(也叫多線程服務(wù)器,MTS)模式下,多個用戶進程可能只對應(yīng)一個服務(wù)進程。
DBWR
DBWR 其實就是DataBase Writer n,如果只有一個,那么n就是0,即進程為DBW0。它是Oracle數(shù)據(jù)庫中一個極其重要的后臺進程,主要負(fù)責(zé)將數(shù)據(jù)緩沖區(qū)內(nèi)的數(shù)據(jù)寫入數(shù)據(jù)文件。其功 能很簡單,僅僅就是寫數(shù)據(jù)緩沖區(qū)內(nèi)的臟數(shù)據(jù),也就是將臟列表(Dirty List)上的數(shù)據(jù)定期寫入數(shù)據(jù)文件,和任何前臺用戶的進程幾乎沒有什么關(guān)系,也不受它們的控制。DBWn工作的主要條件如下:
l?????????? DBWR 超時,大約3秒
l?????????? 系統(tǒng)中沒有多的空緩沖區(qū)來存放數(shù)據(jù)
l?????????? CKPT 進程觸發(fā)DBWn 等
如圖1-7所示,Data buffer可能存放有數(shù)據(jù)塊、Undo數(shù)據(jù)塊、Undo頭等,而DBWn只負(fù)責(zé)寫臟列表的數(shù)據(jù),當(dāng)一個服務(wù)器進程將一緩沖區(qū)移入“弄臟”表,該弄臟表達到臨界長時,該服務(wù)進程將通知DBWn進行寫操作。
圖1-7? DBWn寫進程
另外的情況,當(dāng)一個服務(wù)器進程在LRU表中查找可用的緩沖區(qū)時,到了一定程度,還沒有查到未用的緩沖區(qū),它將停止查找并通知DBWn進行寫操作。
在CKPT的時候,需要根據(jù)檢查點隊列,通知DBWn把檢查點以前SCN的塊寫入數(shù)據(jù)文件,以減少實例的恢復(fù)時間。
LGWR
LGWR也是一個非常重要的后臺進程,主要負(fù)責(zé)將重做日志緩沖區(qū)的數(shù)據(jù)寫入重做日志文件,LGWR是一個必須和前臺用戶進程通信的進程。當(dāng)數(shù)據(jù)被修改的時候,系統(tǒng)會產(chǎn)生一個重做日志并記錄在重做日志緩沖區(qū)內(nèi)。這個Redo記錄的條目大致可以認(rèn)為是:
事務(wù)標(biāo)示Transaction identifier
列信息Column address(File Block Row Column)
列的值Value of the column that changed
而日志緩沖區(qū)是一個循環(huán)緩沖區(qū)。在LGWR將日志緩沖區(qū)的日志項寫入日志文件后,服務(wù)器進程可將新的日志項寫入到該日志緩沖區(qū)。LGWR 通常寫得很快,可確保日志緩沖區(qū)總有空間可寫入新的日志項。
LGWR工作的主要條件如下:
l?????????? 用戶提交
l?????????? 有1/3 重做日志緩沖區(qū)未被寫入磁盤
l?????????? 有大于1MB重做日志緩沖區(qū)未被寫入磁盤
l?????????? 超時
l?????????? DBWR需要寫入數(shù)據(jù)的SCN號大于LGWR記錄的SCN號,DBWR觸發(fā)LGWR寫入
所以,有時候當(dāng)需要更多 的日志緩沖區(qū)時,LWGR在一個事務(wù)提交前就將日志項寫出,而這些日志項僅在事務(wù)提交后才永久化。 Oracle使用快速提交機制,當(dāng)用戶發(fā)出COMMIT語句時,一個COMMIT記錄立即放入聯(lián)機日志文件,但對應(yīng)的數(shù)據(jù)緩沖區(qū)的數(shù)據(jù)塊的改變,也就是上 面說的“臟”數(shù)據(jù),一直要等到滿足條件才被DBWn寫入數(shù)據(jù)文件。這樣做的主要目的就是可以快速提交事務(wù)并返回給用戶提交信息,但是又能確保事務(wù)的完整 性。
當(dāng)事務(wù)提交時,它被賦給 一個系統(tǒng)修改號(SCN),同事務(wù)日志項一起記錄在日志中。在Oracle 中,SCN是一個很重要的概念,貫穿整個Oracle體系結(jié)構(gòu)。下面還會單獨介紹SCN。由于SCN也記錄在日志中,所以,系統(tǒng)故障需要系統(tǒng)恢復(fù)的時候, 就可以很容易地根據(jù)SCN來恢復(fù)。
如圖1-8所示,Log Buffer默認(rèn)大致可以分為三個部分,當(dāng)寫滿其中一個部分,或者是遇到提交的時候,都會導(dǎo)致LGWR寫數(shù)據(jù)。另外,LGWR也會有3s的超時限制,超過 這個時間還沒有寫日志將會強制寫,或者是大于1MB的限制也會強制寫。因此基于以上的限制,在頻繁提交的OLTP系統(tǒng)中,根本不需要有太大的Log buffer。
圖1-8? LGWR寫進程
9i其他的后臺進程
CKPT:檢查點進程,同步數(shù)據(jù)文件、日志文件和控制文件。DBWR/LGWR的工作原理,造成了數(shù)據(jù)文件、日志文件、控制文件的不一致,這就需要CKPT進程來同步。CKPT會通知DBWn進程寫入臟塊,并更新數(shù)據(jù)文件/控制文件的頭信息。
PMON:進程監(jiān)控進程,主要用于清除失效的用戶進程,釋放用戶進程所用的資源。如PMON將回滾未提交的工作,釋放鎖,釋放分配給失敗進程的SGA資源。
SMON:系統(tǒng)監(jiān)控進程,主要負(fù)責(zé)系統(tǒng)啟動時候的實例恢復(fù),管理回滾段的在線與離線工作,管理并清除臨時空間,以及合并空閑空間等。
ARCH:歸檔進程。當(dāng)數(shù)據(jù)庫以歸檔方式運行的時候,Oracle會啟動ARCH進程;當(dāng)重做日志文件被寫滿時,日志文件進行切換,舊的重做日志文件就被ARCH進程復(fù)制到一個/多個特定的目錄/遠程機器。這些被復(fù)制的重做日志文件被叫做歸檔日志文件。
CJQn作業(yè)進程的管理進程,一般是CJQ0,可以自動產(chǎn)生j000-j999類似的作業(yè)進程來運行作業(yè)。
Jnnn作業(yè)進程,負(fù)責(zé)運行具體的作業(yè),如j000,j001。
Pnnn并行進程,一般在并行環(huán)境中自動產(chǎn)生的并行進程,如p000,p001。
Snnn用于共享服務(wù)器(或者叫多線程服務(wù)器,MTS),共享服務(wù)器進程。
Dnnn用戶共享服務(wù)器(MTS),調(diào)度后臺進程。
Oracle 10g中的一些后臺進程
QMNn是Oracle10g以后供 Oracle Streams Advanced Queuing使用的可選進程,用于監(jiān)控消息隊列。
MMON與診斷功能有關(guān)系,如為AWR(Automatic Workload Repository)收集性能數(shù)據(jù)的快照,并維護這些數(shù)據(jù)。
MMNL與診斷功能有關(guān)系,也為AWR服務(wù),其全拼為Memory Monitor Light,會根據(jù)調(diào)度從SGA將統(tǒng)計結(jié)果采集給AWR。
MMAN與Oracle 10g 的新特性,自動SGA管理有關(guān)系,全拼為Memory Manager,在10g負(fù)責(zé)自動管理SGA,11g則負(fù)責(zé)管理整個內(nèi)存(SGA+PGA)。
RBAL負(fù)責(zé)協(xié)調(diào)磁盤組間的負(fù)載平衡工作,在使用了ASM的數(shù)據(jù)庫實例中運行。當(dāng)向ASM磁盤組增加或刪除磁盤 時,RBAL進行負(fù)責(zé)處理重新平衡的請求,它還支持多個實例同時訪問一個 ASM 磁盤(global open),并由 ORBn 進程實際執(zhí)行數(shù)據(jù)遷移的負(fù)載均衡。實例中可以運行多個 ORBn 進程,分別為 ORB0,ORB1,以此類推。
ASMB在使用ASM磁盤組的時候負(fù)責(zé)與ASM實例的通信,向ASM實例提供更新統(tǒng)計信息。
Oracle11g中的一些后臺進程
DBRM數(shù)據(jù)庫資源管理進程,負(fù)責(zé)設(shè)置資源計劃和其他的資源管理工作。
DIAG數(shù)據(jù)庫診斷進程,負(fù)責(zé)維護管理各種用于診斷的轉(zhuǎn)儲文件,并執(zhí)行Oradebug命令。
DIAn另一個數(shù)據(jù)庫診斷進程,負(fù)責(zé)檢測Oracle數(shù)據(jù)庫中的掛起(hang)和死鎖的處理。
PSPn用于產(chǎn)生Oracle進程。
SMCO負(fù)責(zé)空間協(xié)調(diào)管理工作,負(fù)責(zé)執(zhí)行空間的分配和回收。
Wnnn命名為W000,W001,W002……,由SMCO動態(tài)產(chǎn)生執(zhí)行上述相關(guān)任務(wù)。
VKTM用于提供wall-clock time,頻率為每秒鐘更新一次。它還提供每20毫秒更新一次的reference-time counter,有點類似計時器的功能。
SCN
上面介紹LGWR的時候, 我們曾經(jīng)簡單介紹過SCN,SCN(System Change Number)由LGWR在系統(tǒng)提交、超時或者檢查點的時候發(fā)生,表明了一個塊以至于整個數(shù)據(jù)庫的更新時間戳。
Oracle 9i以上版本可以通過如下語句獲得系統(tǒng)當(dāng)前的SCN:
SQL> select DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER SCN from dual;
SCN
-------------
69383617692
SCN可能同時存在于數(shù)據(jù)文 件頭、控制文件頭、聯(lián)機日志、歸檔日志中,甚至是塊的內(nèi)部,是數(shù)據(jù)庫備份與恢復(fù)、表的一致性讀的基礎(chǔ)。通過控制文件與數(shù)據(jù)文件中的SCN,可以知道當(dāng)前的 數(shù)據(jù)文件與控制文件是否同步,是否需要做介質(zhì)恢復(fù);聯(lián)機日志,歸檔日志中的SCN,可以用于數(shù)據(jù)庫的介質(zhì)恢復(fù),如恢復(fù)的統(tǒng)一的SCN點;而數(shù)據(jù)塊中的 SCN,則可以用于數(shù)據(jù)的一致性讀。
SCN有如下特點:
l?????????? 查詢語句不會使SCN增加,就算是同時發(fā)生的更新,數(shù)據(jù)庫內(nèi)部對應(yīng)的SCN也是不同的。這樣一來就保證了數(shù)據(jù)恢復(fù)時的順序。
l?????????? 維持?jǐn)?shù)據(jù)的一致性讀,當(dāng)一個查詢執(zhí)行的時候,它會先從系統(tǒng)中得到一個當(dāng)前的SCN號,在查找數(shù)據(jù)的同時,它會檢查每個數(shù)據(jù)行及其對應(yīng)的SCN號,只有那些 小于或等于它的SCN號的行才能從對應(yīng)用戶數(shù)據(jù)文件的緩沖區(qū)內(nèi)取出,而那些大于它的SCN號的行,就應(yīng)該從回滾段數(shù)據(jù)文件的緩沖區(qū)內(nèi)取出。
1.1.4? 物理結(jié)構(gòu)與邏輯結(jié)構(gòu)
物理結(jié)構(gòu)指物理文件的集合,如數(shù)據(jù)文件、聯(lián)機日志、控制文件、參數(shù)文件等,而邏輯結(jié)構(gòu),則是對用戶可視的邏輯對象,如表、索引,也都是邏輯對象的一種。圖1-9說明了典型的邏輯結(jié)構(gòu)與數(shù)據(jù)文件之間的關(guān)系。
圖1-9? 邏輯結(jié)構(gòu)與數(shù)據(jù)文件
從圖1-9中可以看到,邏輯結(jié)構(gòu)的關(guān)系是:
l?????????? 數(shù)據(jù)庫可以包含多個表空間。
l?????????? 一個表空間(Tablespace)可以有多個數(shù)據(jù)文件(data file),可以存在多個段,但是一個段只能存在于一個單獨的表空間內(nèi)。
l?????????? 一個段(Segment)可以分布在多個數(shù)據(jù)文件中,一個數(shù)據(jù)文件也可以存在多個段。
l?????????? 區(qū)間(Extent)不能跨越在多個數(shù)據(jù)文件上,一個數(shù)據(jù)文件可以包含多個區(qū)間。
l?????????? 一個段可以劃分為多個區(qū)間。
l?????????? 任何一個區(qū)間都是由一系列連續(xù)的塊(Block)組成的,所以一個區(qū)間包含多個數(shù)據(jù)塊。
表空間(Tablespace)
表空間是數(shù)據(jù)庫中最大的邏輯存儲結(jié)構(gòu),為數(shù)據(jù)庫提供使用空間,其對應(yīng)物理結(jié)構(gòu)是數(shù)據(jù)文件,一個表空間可以包含多個數(shù)據(jù)文件,但是一個數(shù)據(jù)文件只能屬于一個表空間。表空間所包含的數(shù)據(jù)文件的大小,也就決定了表空間的大小,所以,表空間也是邏輯結(jié)構(gòu)連接到物理結(jié)構(gòu)的一條紐帶。
作為Oracle一個非常重要的邏輯對象與空間管理對象,表空間所對應(yīng)的高可用管理特性也非常多。本書有很多地方都會介紹表空間的高可用特性,如第10章的表空間遷移,第14章的表空間特性與數(shù)據(jù)文件規(guī)劃,都會詳細(xì)介紹表空間的很多高可用特性。
這里先簡單地介紹一些日常工作中遇到的簡單的表空間管理特性,更多更詳細(xì)的信息請參考本書后面的內(nèi)容。
u????????? 默認(rèn)表空間
在Oracle 9i以前,system表空間是用戶默認(rèn)的表空間,當(dāng)用戶創(chuàng)建一個對象沒有指定特定的表空間的時候,對象將創(chuàng)建在system表空間中。因此,經(jīng)常發(fā)生這樣的情況,system表空間因為這些可能的垃圾對象而變得非常之大,而又沒有一個好的辦法讓它變小。
從Oracle 9i起,這個情況有了一定的變化,系統(tǒng)可以為數(shù)據(jù)庫指定一個默認(rèn)的永久表空間,如果沒有指定特定的表空間,將使用這個默認(rèn)的表空間。
SQL>alter database default tablespace <tbs_names>;
關(guān)于這個值可以從視圖DATABASE_PROPERTIES中獲得,如通過如下語句可以獲知系統(tǒng)當(dāng)前的默認(rèn)表空間是什么。如果以下查詢發(fā)現(xiàn)沒有指定任何默認(rèn)表空間,則數(shù)據(jù)庫還是會使用system作為用戶默認(rèn)的表空間。
SQL>select property_value from database_roperttes
where property_name = 'DEFAULT_PERMANENT_TABLESPACE';
除了數(shù)據(jù)庫可以統(tǒng)一指定以外,用戶也可以在創(chuàng)建的時候,或者后期通過如下的命令指定默認(rèn)的用戶默認(rèn)表空間,如
SQL>alter user taobao default tablespace <tbs_name>;
u?????? 不同塊大小支持
為了支持在不同塊大小的數(shù)據(jù)庫上傳輸表空間,Oracle 從9i開始,可以支持在一個數(shù)據(jù)庫中存在不同塊大小的表空間。
除了傳輸表空間以外,也可以手工創(chuàng)建不同塊大小的表空間,需要在創(chuàng)建表空間的時候,指定blocksize <塊大小>參數(shù)。如
SQL>create tablespace tbs_name
datafile 'data file name' size 1024M reuse blocksize 2048;
如果存在不同塊大小的表空間,則需要指定特定的Data buffer,如在本章介紹Data buffer時曾經(jīng)介紹過的db_nk_cache_szie參數(shù)。
u????????? 重命名表空間
在Oracle 10g以前,數(shù)據(jù)庫并不提供重命名表空間的操作,但是,隨著傳輸表空間使用的越來越頻繁,如果源數(shù)據(jù)庫與目標(biāo)數(shù)據(jù)庫的表空間名稱存在重名沖突,將使傳輸表空間變得困難。
其實,主要是為了解決這個問題,從Oracle 10g起可以重命名表空間,這個特性使得重名沖突下傳輸表空間變得很簡單了。該操作可以針對任何永久表空間及臨時表空間,重命名的語法為:
SQL>alter tablespace <old_tbs_name> rename to <new_tbs_name>;
另外,Oracle還會智能地幫助DBA或維護者完成配套的修改工作,例如,這個表空間如果是數(shù)據(jù)庫或用戶默認(rèn)表空間,則在對應(yīng)的數(shù)據(jù)字典中也會發(fā)生改變。甚至,如果重命名默認(rèn)的Undo表空間,spfile都會發(fā)生對應(yīng)的變化。
u????????? 刪除表空間中的文件
在Oracle 10gR2以前,如果在一個表空間中意外地創(chuàng)建了一個數(shù)據(jù)文件,雖然這個數(shù)據(jù)文件還是空的,上面沒有任何東西,但是想刪除它非常困難,而且基本上不可能實現(xiàn)。
一般的做法是Offline該數(shù)據(jù)文件,并把它修改為非常小的一個空間,但是即使這樣,這個數(shù)據(jù)文件還是存在的,只不過是數(shù)據(jù)庫以后不再訪問這個數(shù)據(jù)文件,并且不再更新其SCN,但是這個數(shù)據(jù)文件不能丟失,也不能手工刪除。
在Oracle 10gR2以后,可以通過如下的命令來刪除一個多余的數(shù)據(jù)文件,這個命令對于很多誤操作,對于高可用系統(tǒng)的管理,都是一個好的消息。具體命令為:
SQL>alter tablespace tbs_name drop datafile 'data file name'
當(dāng)然,如果想刪除該數(shù)據(jù)文件,必須保證數(shù)據(jù)文件為空,而且,如果該表空間只有一個數(shù)據(jù)文件,則無法刪除這個數(shù)據(jù)文件,只能刪除表空間。在把數(shù)據(jù)文件真正從表空間中刪除以前,還是建議先offline該數(shù)據(jù)文件。
SQL>alter database datafile 'data file name' offlien [drop];
段(segment)
段是Oracle另外一個很重要的邏輯對象,一個段可以跨越在多個數(shù)據(jù)文件中,但是,一個段只能在一個表空間中。在一個段中,至少存在一個Extent,對于單獨的Extent,必須是連續(xù)的空間,而且只能存在一個數(shù)據(jù)文件中。常見的段類型有以下幾種。
l?????????? 表段:表示未分區(qū)的表對應(yīng)的段,一個未分區(qū)的表一般就是一個段。
l?????????? 索引段:表示一個未分區(qū)的索引,就是一個索引段。
l?????????? 表分區(qū)段:如果一個表分成多個區(qū),那么,每個區(qū)對應(yīng)一個表分區(qū)段。
l?????????? 索引分區(qū)段:包括本地索引及分區(qū)的全局索引,每個區(qū)對應(yīng)一個索引分區(qū)段。
l?????????? 臨時段:存在于臨時表空間,或者永久表空間的臨時用途,用完后能馬上釋放。
l?????????? 回滾段:用于存放Undo數(shù)據(jù),也叫Undo段,9i以上開始自動管理。
l?????????? LOB段:存放LOB數(shù)據(jù)的段,如果一個表有LOB字段,每個LOB字段可能還會分離出兩個段,LOB段與LOB index段。
如在某個含一個LOB字段的分區(qū)表內(nèi)創(chuàng)建一個本地索引,假定分區(qū)個數(shù)為N,則該表與本地索引對應(yīng)的段有:
l?????????? N個表的分區(qū)段。
l?????????? N個索引分區(qū)段,如果本地索引個數(shù)為M,則索引段的個數(shù)為N*M個。
l?????????? N個LOB index段與N個LOB data段,如果LOB字段個數(shù)為M,那么,LOB索引與LOB數(shù)據(jù)段分別為N*M個。如創(chuàng)建一個有3個分區(qū)的表,包含一個本地索引,包含一個LOB字典,則合計應(yīng)當(dāng)有12個段。
SQL> create table test(id number,create_time date,testlob blob)
2????? partition by range (id)
3?????? (partition TEST_PART1 values less than (100),
4?????? partition TEST_PART2 values less than (200),
5?????? partition TEST_PART3 values less than (maxvalue));
Table created.
SQL> create index ind_test on test (id) local;
Index created.
SQL> select segment_name,partition_name,segment_type from user_segments;
SEGMENT_NAME???????????? ? PARTITION_NAME????? SEGMENT_TYPE
------------------------- ------------------ ------------------
TEST???????????????????? ? TEST_PART1?????????? TABLE PARTITION
TEST???????????????????? ? TEST_PART2?? ????????TABLE PARTITION
TEST???????????????????? ? TEST_PART3?????????? TABLE PARTITION
SYS_LOB0000012033C00003$$ SYS_LOB_P21????????? LOB PARTITION
SYS_LOB0000012033C00003$$ SYS_LOB_P22????????? LOB PARTITION
SYS_LOB0000012033C00003$$ SYS_LOB_P23????????? LOB PARTITION
SYS_IL0000012033C00003$$ ? SYS_IL_P24?????????? INDEX PARTITION
SYS_IL0000012033C00003$$ ? SYS_IL_P25?????????? INDEX PARTITION
SYS_IL0000012033C00003$$ ? SYS_IL_P26?????????? INDEX PARTITION
IND_TEST???????????????? ? TEST_PART1?????????? INDEX PARTITION
IND_TEST???????????????? ? TEST_PART2?????????? INDEX PARTITION
IND_TEST???????????????? ? TEST_PART3?????????? INDEX PARTITION
12 rows selected.
另外,每一個段在數(shù)據(jù)字典中,都會有一個唯一的標(biāo)示,即data_object_id,它與object_id的差別 是,object_id針對的是對象,而data_object_id針對的是段。如一些對象,如存儲過程、函數(shù)等,它們不是段,則只有 object_id而沒有data_object_id。
注意:不是每個對象都會有object_id,如db link,但是,每個段肯定都有data_object_id,因為一個段肯定屬于一個表空間,所以根據(jù)data_object_id就能唯一確定該段所在的表空間,這個就是Rowid組成的基礎(chǔ)知識。
如果段的物理存儲屬性發(fā)生變化,如在有數(shù)據(jù)情況下被truncate、move、rebuild等操作,data_ object_id是會發(fā)生變化的,而object_id一旦產(chǎn)生,則不會發(fā)生改變,除非是刪除該對象。如:
SQL> select object_name,subobject_name,object_type,object_id,data_object_id
2???? from user_objects;
OBJECT_NAME?????????????? ???SUBOBJECT_NAME ??OBJECT_TYPE????? ??OBJECT_ID ??DATA_OBJECT_ID
------------------------- --------------- --------------- ---------- --------------
TEST?????? ????????????? ? TEST_PART2?????? TABLE PARTITION??? 12035????????? ??12035
TEST???????????????????? ? TEST_PART3?????? TABLE PARTITION??? 12036????????? ??12036
TEST???????????????????? ? TEST_PART1?????? TABLE PARTITION ?? 12034????????? ??12034
TEST?????????????????????????????????????? TABLE????????????? 12033
SYS_IL0000012033C00003$$? ?SYS_IL_P26?????? INDEX PARTITION??? 12044????????? ??12044
SYS_IL0000012033C00003$$? ?SYS_IL_P25?????? INDEX PARTITION??? 12043????????? ??12043
SYS_IL0000012033C00003$$? ?SYS_IL_P24?????? INDEX PARTITION??? 12042????????? ??12042
SYS_LOB0000012033C00003$$ ?SYS_LOB_P23????? LOB PARTITION????? 12040????????? ??12040
SYS_LOB0000012033C00003$$ ?SYS_LOB_P22????? LOB PARTITION????? 12039????????? ??12039
SYS_LOB0000012033C00003$$ ?SYS_LOB_P21????? LOB PARTITION????? 12038????????? ??12038
SYS_LOB0000012033C00003$$????????????????? LOB??????????????? 12037????????? ??12037
IND_TEST???????????????? ? TEST_PART3?????? INDEX PARTITION??? 12048????????? ??12048
IND_TEST???????????????? ? TEST_PART2?????? INDEX PARTITION??? 12047????????? ??12047
IND_TEST???????????????? ? TEST_PART1?????? INDEX PARTITION??? 12046????????? ??12046
IND_TEST?????????????????????????????????? INDEX????????????? 12045
現(xiàn)在,插入幾條記錄,并truncate該表,可以看到:
SQL> insert into test values(1,sysdate,'1');
1 row created.
SQL> insert into test values(1,sysdate,'110');
1 row created.
SQL> commit;
Commit complete.
SQL> truncate table test;
Table truncated.
SQL> select object_name,subobject_name,object_type,object_id,data_object_id
2??????? from user_objects;
OBJECT_NAME?????????????? ???SUBOBJECT_NAME? ?OBJECT_TYPE????? ?OBJECT_ID DATA_OBJECT_ID
------------------------- --------------- --------------- ---------- --------------
TEST????????????????????? ????TEST_PART2????? ? TABLE PARTITION???? ?12035????????? ??12052
TEST????????????????????? ????TEST_PART3???? ?? TABLE PARTITION????? 12036????????? ??12036
TEST????????????????????? ????TEST_PART1????? ? TABLE PARTITION????? 12034????????? ??12051
TEST????????????????????????????????????? ??????? TABLE ?????????????????12033
SYS_IL0000012033C00003$$ SYS_IL_P26????? ??INDEX PARTITION????? 12044????????? ??12044
SYS_IL0000012033C00003$$ SYS_IL_P25????? ??INDEX PARTITION????? 12043????????? ??12043
SYS_IL0000012033C00003$$ SYS_IL_P24????? ??INDEX PARTITION????? 12042????????? ??12042
SYS_LOB0000012033C00003$$ SYS_LOB_P23? ??? ?LOB PARTITION??????? 12040????????? ??12040
SYS_LOB0000012033C00003$$ SYS_LOB_P22???? ??LOB PARTITION??????? 12039????????? ??12039
SYS_LOB0000012033C00003$$ SYS_LOB_P21???? ??LOB PARTITION??????? 12038????????? ??12038
SYS_LOB0000012033C00003$$????????????? ??? ?LOB???????????????? 12037????????? ??12037
IND_TEST????????????????? ?? TEST_PART3?? ??? ?INDEX PARTITION???? ?12048????????? ??12054
IND_TEST????????????????? ?? TEST_PART2?? ??? ?INDEX PARTITION???? ?12047????????? ??12047
IND_TEST????????????????? ?? TEST_PART1?? ??? ?INDEX PARTITION???? ?12046????????? ??12053
IND_TEST?????????????????????????????? ??? ?INDEX??????????????? ??12045
可以看到,在truncate之前,這些段data_object_id與object_id還是相等的,但是 truncate之后,表與索引的data_object_id都發(fā)生了變化。因為data_object_id 是與段的存儲屬性有關(guān)的,這里表示Oracle可能重新分配過一次空間,雖然空間分配可能就是在原地,段頭的位置并沒有發(fā)生變化,但是 data_object_id還是會變。
另外,還可以發(fā)現(xiàn),如果這個段中沒有任何數(shù)據(jù),如上面的TEST_PART3,就算發(fā)生了 truncate,data_object_id也沒有變化。只有存在數(shù)據(jù)的段,如上面的TEST_PART1與TEST_PART2,發(fā)生 truncate的時候,data_object_id才會發(fā)生改變。
塊(Block)
Block概述
上面介紹了Oracle兩個非常重要的邏輯對象——表空間與段,現(xiàn)在介紹Oracle最基本的邏輯對象,也是Oracle 最小的存儲單位——數(shù)據(jù)塊。數(shù)據(jù)塊大小在建立數(shù)據(jù)庫的時候指定,雖然在初始化文件中可見,但是不能修改。為了保證存取的速度,它是OS數(shù)據(jù)塊的整數(shù) 倍,Oracle的所有存儲IO操作都是以塊為基本單位的。
在Oracle 9iR2之前,一個Oracle數(shù)據(jù)庫中只能存在一個類型的塊大小,從Oracle 9iR2 開始,才取消了這個限制。
塊的內(nèi)部結(jié)構(gòu)與數(shù)據(jù)的存取方法都是比較復(fù)雜的,以表段的塊為例,從簡單的結(jié)構(gòu)上劃分,可以把塊的內(nèi)部劃分成如下幾個部分:塊頭(Block Header)、表目錄(Table Directory)、行目錄(Row Directory)、可存取空間等。
圖1-10是一個表塊的大致結(jié)構(gòu):
圖1-10? 表塊的大致結(jié)構(gòu)
塊頭(Block Header)包含著關(guān)于塊類型(表塊、索引塊等等)的信息、塊上活動和過時事務(wù)信息、磁盤上塊地址信息,其中的transaction Layer決定了該塊可以并發(fā)操作的事務(wù)數(shù),其大小由init trans存儲參數(shù)決定,而Variable大小由Max trans決定。如果設(shè)置了不恰當(dāng)?shù)膇nit trans與max trans,可能導(dǎo)致該塊在進行大批量并發(fā)操作出現(xiàn)嚴(yán)重ITL等待,甚至爆發(fā)ITL死鎖。關(guān)于ITL與ITL死鎖,在本書的第14章將有詳細(xì)的介紹。
表目錄(Table directory),包含著此塊中存儲各行的表的信息(多個表的數(shù)據(jù)可能保存在同一個塊中,如cluster table)。行目錄(Row directory)包含在塊中發(fā)現(xiàn)的描述行的信息。以上三部分為塊的開銷(Block Overhead),其余部分為可用存儲空間,可以用如下查詢獲得可用空間大小。
SQL>Select kvisval,kvistag,kvisdsc from sys.x$kvis;
可以看到,一般的8K(8192)的塊可用空間為8096字節(jié)。
在手動段管理模式(MSSM)下,PCTFREE與PCTUSED是表的兩個存取參數(shù),其實是作用在表 中的塊上面的,PCTFREE與PCTUSED表示兩個百分比,默認(rèn)分別是10與40。PCTFREE表示保留該百分比的可用空間用于以后的行更新,避免 行遷移。如果行數(shù)據(jù)達到PCTFREE保留的空間,該塊從FREE LIST上撤消,不再接收數(shù)據(jù)。PCTUSED表示當(dāng)行的空閑空間降低(如刪除數(shù)據(jù))到該參數(shù)指定的百分比時,該塊重新進入FREE LIST,開始接收新的數(shù)據(jù)。
而在自動段管理模式(ASSM)下,PCTUSED參數(shù)被取消,空間的使用率與塊的重用將采用另外的算法來進行。
Block的行限制
一個8K的塊的可用空間雖然有8096字節(jié),那如果插入1字節(jié)一行的數(shù)據(jù),是否可以插入8000多行呢?答案是否定的,因為每行的其他開銷導(dǎo)致每行的最小長度在11字節(jié)左右,所以一個8K塊的行理論上最多可以存儲8096/11=736行。具體可以看如下的實驗過程:
這里先創(chuàng)建一個8K字節(jié)大小的MSSM管理模式的表空間,并且設(shè)置PCTFREE為0,這樣的話,可以最大限度地插入記錄,而不保留任何空間。
Piner@Ora9iR2:8K>create table test(a varchar2(1)) pctfree 0 TABLESPACE TBS_MSSM;
Table created.
先可以看看這個塊大小,理論上可以插入的最大記錄數(shù)。
Piner@Ora9iR2:8K>select object_id from dba_objects where object_name='TEST';
OBJECT_ID
----------
66921
Piner@Ora9iR2:8K>SELECT SPARE1 FROM sys.TAB$ WHERE OBJ#=66921;
SPARE1
----------
736
以下的sys_op_rpb函數(shù)是一個未公布的函數(shù),表示查詢指定的表中數(shù)據(jù)塊最大已經(jīng)達到的記錄數(shù),如果沒有任何記錄,則返回NULL。
Piner@Ora9iR2:8K>select max(sys_op_rpb(rowid)) from test;
MAX(SYS_OP_RPB(ROWID))
----------------------
注意:對于未公開的函數(shù),作者不保證該函數(shù)不發(fā)生任何意外的問題,需要各位讀者小心使用。
現(xiàn)在,在剛才創(chuàng)建的表中,插入6000條記錄,值都是1。因為是varchar2(1),所以,每行其實只有1個字節(jié)的行長度。
Piner@Ora9iR2:8K>begin
2????? for i in 1..6000 loop
3????? insert into test values('1');
4????? end loop;
5????? commit;
6? end;
7? /
PL/SQL procedure successfully completed.
再通過sys_op_rpb函數(shù)查詢,可以看到數(shù)據(jù)塊最大保存到的記錄數(shù)為733條。
Piner@Ora9iR2:8K>select max(sys_op_rpb(rowid)) from test;
MAX(SYS_OP_RPB(ROWID))
----------------------
733
其實,通過分析Rowid,完全可以證明這一點:
Piner@Ora9iR2:8K>select f,b,count(*) from (
2? ?select dbms_rowid.rowid_relative_fno(rowid) f,
3???? dbms_rowid.rowid_block_number(rowid) b
4? ???from test) group by f,b;
F???????? ???B?? ?COUNT(*)
---------- ---------- ----------
11????? ?39945??????? ??734
11????? ?39946??????? ??128
11????? ?50434??????? ??734
11????? ?50435??????? ??734
11????? ?50436??????? ??734
11????? ?50437??????? ??734
11????? ?50438??????? ??734
11????? ?50439??????? ??734
11????? ?50440??????? ??734
9 rows selected.
Rowid與Rdba
在上面的例子中,用到Rowid來分析數(shù)據(jù)分布。關(guān)于Rowid,在本書的很多章節(jié)都會使用。Rowid表示一個行的物理 地址,一行一旦插入數(shù)據(jù)庫的塊中,Rowid就已經(jīng)唯一確定,只要不發(fā)生行的物理移動,這行的Rowid是不會發(fā)生任何變化的。Rowid不真正存在于表 數(shù)據(jù)塊中,但是會存在于索引中,方便根據(jù)索引中的Rowid找到表數(shù)據(jù)。
Rwoid只有在行的物理位置發(fā)生改變的情況下才變化,如表的Move、Flashback table、分區(qū)表的行分區(qū)間移動等等。而行鏈接與行遷移等塊的內(nèi)部變化,變化的僅僅是指針,而不會使行的Rowid變化。
Oracle 8以下Rowid組成(也叫受限Rowid)為:FFFF.BBBBBBBB.RRRR,占用6個字節(jié)(10bit file#+22bit+16bit),但是,為了擴充的需要(如數(shù)據(jù)文件的擴充),現(xiàn)在的Rowid改為:OOOOOOFFFBBBBBBRRR,占用 10個字節(jié)(32bit+10bit rfile#+22bit+16bit)。其中,O是對象ID,F是文件ID,B是塊ID,R是行ID。由于Rowid組成從file#變成了 rfile#,所以數(shù)據(jù)文件數(shù)的限制也從整個庫不能超過1023個變成了每個表空間不能超過1023個數(shù)據(jù)文件。
注 意:這里的O代表上面提到的data_object_id,是與段物理存儲位置相關(guān)的一個信息,因為一個段對象只可能在一個表空間 上,data_object_id能唯一確認(rèn)ts#,而data_object_id + rfile#就能最終定位該Rowid到那個確定的物理數(shù)據(jù)文件。剩下的塊地址與塊內(nèi)的行地址,就可以定位到具體的記錄了。
Oracle 8以下的版本,FFFF表示物理文件號file#,因此,Rowid就限制了每個數(shù)據(jù)庫不能超過1023個數(shù)據(jù)文件,因為超過了該限制Rowid就無法表示了。
在Oracle 8以上,因為引入了OOOOOO代表data_object_id,而data_object_id對應(yīng)特定的物理表空間,所以,OOOOOO+FFF就 決定了每個表空間只要數(shù)據(jù)文件不超過1023個即可。為了向下兼容,引入了一個新的編號,rfile#,也叫相對文件號。就是說,這個rfile#是跟 Oracle 8以前的file#一樣,值為1~1023。而Oracle 8以后的file#,則可以一直往下增長。
關(guān)于file#與rfile#的關(guān)系,可以從如下的視圖中獲得
select file#,rfile# from v$datafile
......
FILE#???? ?RFILE#
---------- ----------
1020?????? ??1020
1021?????? ??1021
1022?????? ??1022
1023?????? ??1023
1024???????? ????1
1025????????? ???2
1026????????? ???3
......
可以看到,如果file#,也就是數(shù)據(jù)文件編號file_id超過了1023,相對文件編號rfile#則重新歸1,又從1開始計算,一直循環(huán)下去。
注 意:因為Rowid中采用的是rfile#,所以,從Rowid中獲得的file id不一定代表真實的file id,只能說是代表了rfile#。從上面的視圖也可以看到,如果數(shù)據(jù)文件個數(shù)在1023以內(nèi),則file#=rfile#,只要整個數(shù)據(jù)庫的數(shù)據(jù)文件沒 有超過1023,可以認(rèn)為它們是等同的。
查詢一個表的Rowid,就可以獲得object的信息、相對文件編號信息、塊信息與行信息等等。
用例子說明一下Rowid的組成:
SQL> select rowid from test where rownum = 1;?
AAAAeNAADAAAAWZAAA
分解一下,可以看到:
Data Object number = AAAAeN
File????????????? ????= AAD
Block??????????? ?????= AAAAWZ
ROW????????????? ?????= AAA
另外,我們需要注意的是,ROWID是64進制的,分布關(guān)系如下:
A-Z <==> 0 ?- 25 (26)
a-z <==> 26 - 51 (26)
0-9 <==> 52 - 61 (10)
+/ ?<==> ?62 - 63 (2)
拿其中的Data Object number= AAAAeN為例子,
N是64進制中的13,位置為0
13 * (64 ^ 0) = 13
E是64進制中的30,位置為1
30 * (64 ^ 1) = 1920
A是64進制中的 0
所以
A * (64 ^ 2) = 0
A * (64 ^ 3) = 0
A * (64 ^ 4) = 0
A * (64 ^ 5) = 0
則有AAAAeN = 0 + 0 + 0 + 0 + 1920 + 13 = 1933,表示該行存在的對象,對應(yīng)的對象號為1933。
而且,也可以利用Oracle提供的包——dbms_rowid來做到這一點:
select dbms_rowid.rowid_object('AAAAeNAADAAAAWZAAA') data_object_id#,
dbms_rowid.rowid_relative_fno('AAAAeNAADAAAAWZAAA') rfile#,
dbms_rowid.rowid_block_number('AAAAeNAADAAAAWZAAA') block#,
dbms_rowid.rowid_row_number('AAAAeNAADAAAAWZAAA') row# from dual;
DATA_OBJECT_ID#???? ?RFILE#???? ?BLOCK#?????? ?ROW#
--------------- ---------- ---------- ----------
1933????????? ??3? ???????1433????????? ??0
Oracle 8以后的普通索引或本地索引,因為每一個索引段可以對應(yīng)到一個具體的表段或表分區(qū)段,然后根據(jù)這個對應(yīng)關(guān)系定位到索引所在的表空間,所以,這些索引中其實 保存的還是原始的6個字節(jié)的Rowid。而全局索引因為不能對應(yīng)到具體的表段,所以全局索引中,必須保證10個字節(jié)的Rowid。
正是因為索引要另外保存一個Rowid,這也就是有的時候索引剛創(chuàng)建出來就比表大的原因。
如果明白了以上Rowid的含義,那么就很容易理解塊的地址——rdba了,其實,塊的地址就是Rowid中的FFFBBBBBB部分,10bit rfile#+22bit,如分析一個塊地址:
DBA: 0x2fc0100a
那么,把0x2fc0100a轉(zhuǎn)換成二進制為
2??? ?f??? ?c??? ?0??? ?1??? 0?? ?0??? ?a??
0010 1111 1100 0000 0001 0000 0000 1010
再次轉(zhuǎn)換
0010 1111 11??????????????? 00 0000 0001 0000 0000 1010
------------????????????? ??---------------------------
數(shù)據(jù)文件id????? ??????????????塊ID
191(十進制)???????????????? 4106(十進制)
或者是通過如下的方法,0x2fc0100a = 十進制的801116170
SQL> select dbms_utility.data_block_address_file(801116170) "file",
2???????? ??dbms_utility.data_block_address_block(801116170) "block"?
3???????? ??from dual;
file????? ?block
---------- ----------
191?????? ?4106
因為這里得到的191是rfile#,相對文件號,而相對文件號不能超過1023,所以,如果想根據(jù)這個地址來dump數(shù)據(jù)文件塊的話,最好還是核對一下v$datafile:
SQL>select file# from v$datafile where rfile# = 191 and ts# = <:dbfile_in_ts>
如通過以下語句核對
SQL>select file# from v$datafile where rfile# = 191 and ts# = 9;
FILE#
----------
1214
這里的9代表該數(shù)據(jù)文件所在的表空間編號,你可能會驚奇地發(fā)現(xiàn),這個塊地址真正的數(shù)據(jù)文件編號應(yīng)當(dāng)是1214,而不是上面轉(zhuǎn)換得到的191。
不過一般的情況下,數(shù)據(jù)庫的數(shù)據(jù)文件都沒有1023個,所以這個時候的數(shù)據(jù)文件編號file#與rfile#基本是對應(yīng)的。
這個時候,如果得到了完整的數(shù)據(jù)文件與塊編號,就可以采用如下方式來dump該數(shù)據(jù)塊了。
SQL>alter system dump datafile 1214 block 4106;
1.2.1? 什么是高可用
高可用(HA)有兩種不同的含義,在廣義環(huán)境中,是指整個系統(tǒng)的高可用(High Availability)性,在狹義方面,一般指主機的冗余接管,如主機HA,如果不特殊說明,本書中的HA都指廣義的高可用性。在高可用的解釋方面,可以分為如下一些方面:
(1)系統(tǒng)失敗或崩潰(System faults and crashes)
(2)應(yīng)用層或者中間層錯誤(Application and middleware failures)
(3)網(wǎng)絡(luò)失敗(Network failures)
(4)介質(zhì)失敗,一般指存放數(shù)據(jù)的媒體介質(zhì)故障(Media failures)
(5)人為失誤(Human Error)
(6)分級與容災(zāi)(Disasters and extended outages)
(7)計劃宕機與維護(Planned downtime, maintenance and management tasks)
可見,高可用不僅僅包含了系 統(tǒng)本身故障、應(yīng)用層的錯誤、網(wǎng)絡(luò)錯誤、人為錯誤等,還應(yīng)當(dāng)包括數(shù)據(jù)冗余、容災(zāi)及計劃的維護時間,也就是說,一個真正的高可用環(huán)境,不僅僅能避免系統(tǒng)本身的 問題,還應(yīng)當(dāng)能防止天災(zāi)人禍,并且有一個簡單可靠的系統(tǒng)維護方法如微碼升級、軟件升級等計劃停機維護。
本書定位在Oracle數(shù)據(jù)庫層面上的高可用性,同時也會介紹一些如主機、存儲、操作系統(tǒng)、分級存儲、容災(zāi)方面的高可用性與業(yè)務(wù)連續(xù)性保證。除了應(yīng)用層及中間層的高可用性僅僅是在本章后面有一定的描述以外,其他部分在本書其他章節(jié)都有一定的介紹。
高可用的計算方法一般以年在 線率來計算,如規(guī)定整個系統(tǒng)一年之中的可用環(huán)境要達到99.95%,那么24*365*(1-99.95%)=4.38小時(包括計劃內(nèi)維護時間)。另 外,子系統(tǒng)的可用性一定會高于整個系統(tǒng)的可用性,如承接前面規(guī)定整個系統(tǒng)的可用率為99.95%,那么對于數(shù)據(jù)庫子系統(tǒng),可用性很可能就是要求達到 99.99%。高可用性的在線率(可用級別)與停機時間可以參考如圖1-11所示的對照表:
圖1-11? 高可用級別對照表
基于以上的規(guī)定,假定一個系統(tǒng)一年之中故障時間是1小時(差不多99.99%),但是計劃內(nèi)維護時間卻花了20小時,那么這個系統(tǒng)也不能算是一個滿足設(shè)計要求的高可用環(huán)境。
現(xiàn)階段使用環(huán)境中,基本沒有真正的100%的在線環(huán)境,或者說,如果達到100%的在線能力,要付出非常大的代價,所以一般能達到99.9%以上的可用性的環(huán)境,一般都可以認(rèn)為是比較高的可用環(huán)境了。
對于高可用性在線效率的計算,可以參考如圖1-12所示的方法:
圖1-12? 收益與成本
在公司收益與投入成本計算方面取得一個平衡,則是最終所希望的在線效率,但是收益與成本的計算方法則是決策者與實施者需要著重考慮的問題了。本書的很多地方,其實也希望能提供一種思想,那就是怎樣搭建最適合自己的高可用環(huán)境,而不是盲目地去追逐最高可用性。
1.2.2? Oracle最高可用性體系結(jié)構(gòu)(MAA)
隨著Oracle 9i/10g/11g的更多高可用特性的出現(xiàn),Oracle也推出了它自己的高可用概念,那就是Oracle 最高可用性體系結(jié)構(gòu)(Oracle Maximum Availability Architecture,MAA)。它是Oracle提供的全套的高可用解決方案,由Oracle已經(jīng)在使用的高可用特性組成,目標(biāo)是消除設(shè)計最優(yōu)高可 用性體系結(jié)構(gòu)時的復(fù)雜性。
Oracle 的MAA從非計劃宕機到計劃內(nèi)的停機維護說明了高可用的保證,在MAA體系結(jié)構(gòu)中,可以分為如下4個部分。
u???????? 非計劃宕機
l?????????? 系統(tǒng)失敗:RAC
l?????????? 數(shù)據(jù)異常:Data guard、ASM、Flashback、Rman、Streams
u???????? 計劃內(nèi)停機
l?????????? 系統(tǒng)改變:在線修改配置,在線滾動補丁升級
l?????????? 數(shù)據(jù)變化:在線重定義
以上內(nèi)容在本書都會有詳細(xì)的描述,如第4章將專門介紹RAC與ASM;第5章專門介紹Data guard;第6章專門介紹Streams;第8章介紹了Flashback;第九章介紹了RMAN。
至于計劃內(nèi)停機的一些可用性,可以從如下幾個方面考慮:
l?????????? 在線修改配置的特性,如ASM動態(tài)增加移動硬盤,Oracle內(nèi)存或SGA的在線調(diào)整,RAC動態(tài)增加與刪除節(jié)點。
l?????????? 在線滾動補丁升級的特性,如RAC環(huán)境的滾動升級,Data guard環(huán)境的滾動升級。
l?????????? 在線重定義特性,如在線重定義表,在線rebuild索引等等。
以上的這些特性,在本書不同的地方也有詳細(xì)的描述。
因為本書不僅僅是基于Oracle本身的高可用特性,也包括Oracle數(shù)據(jù)庫的輔助環(huán)境的高可用性,所以介紹的范圍會更廣泛,將包含存儲、主機等很多輔助環(huán)境。
不過,Oracle推出MAA計劃,也表示了它對高可用性方面的重視,特別是從Oracle 9i/10g/11g看來,很多特性都是為高可用性準(zhǔn)備的。可以這么說,Oracle 8i/9i開始出現(xiàn)很多高可用的特性,而在Oracle 10g/11g中,它們更完善、更可靠了。圖1-13是一個典型的Oracle MAA體系結(jié)構(gòu)。
圖1-13? 典型的Oracle MAA結(jié)構(gòu)
在該體系結(jié)構(gòu)中,數(shù)據(jù)庫采用 了RAC+ASM+STANDBY的結(jié)構(gòu)體系,應(yīng)用層采用Oracle自己的Application Server。用戶通過負(fù)載均衡設(shè)備訪問不同的Oracle應(yīng)用服務(wù)器,而應(yīng)用服務(wù)器通過自動負(fù)載均衡及Failover特性訪問當(dāng)前的主數(shù)據(jù)庫。
當(dāng)主站點出現(xiàn)故障的時候,Data guard可以手工或者是自動切換到備用端,應(yīng)用服務(wù)器的訪問也將自動被切換到備用站點,以保證系統(tǒng)的最大可用性與業(yè)務(wù)連續(xù)性。
1.2.3? Oracle高可用相關(guān)功能的產(chǎn)品概述
Oracle提供的高可用相關(guān)產(chǎn)品主要有下面幾種:
(1)Oracle Parallel Server(8i)/ Real Application Cluster(9i/10g/11g)
(2)Oracle Standby Database(8i)/Oracle Data Guard(9i/10g/11g)
(3)Oralce Advanced Replication(8i)/Oracle Stream(9i/10g/11g)
(4)Oracle Server HA
(5)Other: Mv/RMAN/Oracle Log Miner/Oracle Flashback Query(9i/10g/11g)
等等。本章先對前4個主要的高可用特性進行簡單介紹,為本書以后的章節(jié)做一個鋪墊。
Oracle并行數(shù)據(jù)庫OPS /RAC
OPS從Oracle 8開始提供,從Oracle 9i起開始稱為RAC,作為本地環(huán)境高可用的典型代表,OPS/RAC設(shè)計初衷就是系統(tǒng)與應(yīng)用的高可用(System/Application high availability)。與其他產(chǎn)品相比,OPS/RAC是多個服務(wù)器的Cluster,組成具有更大計算處理能力與故障處理能力的集群。 Cluster里面不同的節(jié)點(node) 使用一個(一般是一個)或多個Oracle實例(instances)與一個數(shù)據(jù)庫(database)連接,該數(shù)據(jù)庫存放于多個節(jié)點的公用存儲 (Shared Storage)上。
提醒:因為OPS的技術(shù)不夠完善,如果不作特殊指定,本書介紹的都是Oracle 9i以后的RAC環(huán)境。
主要的技術(shù)特點:
(1)Database 所有的Data files 是建立在共享存儲(Shared Storage)上面的,一般可以采用RAW設(shè)備、共享文件系統(tǒng)或ASM(Oracle 10g以后開始提供)。在早期的版本中,對Cluster軟件依賴性比較高,不過從9i/10g開始,Oracle也不斷地開發(fā)了自己的Cluster軟 件與存儲管理,如OCFS、CRS、ASM都是為RAC而準(zhǔn)備的,并且不斷地完善,也開始被廣泛使用。
(2)RAC在共享存儲方面 并沒有冗余保護,在共享存儲陣列損壞的情況下不具備切換的能力,因此媒體介質(zhì)損壞(Media failure)方面,要依靠RAID(redundant array of inexpensive disk) Subsystem、ASM、LV鏡像(LV Mirror)、卷復(fù)制(Volume Replication)或Standby/Data guard來實現(xiàn)數(shù)據(jù)的冗余保護。
(3)該技術(shù)是Oracle 近來主推的技術(shù),特別是10g以后的網(wǎng)格計算與線型擴展能力,在電信、移動、銀行等行業(yè)使用廣泛。10g以后RAC的線形擴展能力,可以把負(fù)載均衡分布到 多個節(jié)點實現(xiàn)共同計算,使RAC在數(shù)據(jù)倉庫環(huán)境(OLAP)上也開始大量使用。如果還是老的OPS,則不建議使用,Oracle 9i的RAC也或多或少有一些問題,但是Oracle 10g以后的RAC技術(shù)逐漸成熟,基本可以大范圍使用了。
不過,RAC在高可用環(huán)境下的管理成本與技術(shù)的復(fù)雜性,也是需要考慮的。
如圖1-14所示,最理想的RAC環(huán)境,其實就是10g以后提出來的網(wǎng)格計算的概念,在存儲層采用ASM實現(xiàn)可擴充性的存儲網(wǎng)格計算。ASM在這里可以實現(xiàn)數(shù)據(jù)的分布、鏡像及自動負(fù)載均衡等。
圖1-14? RAC網(wǎng)格計算
在中間層實現(xiàn)了數(shù)據(jù)庫的可伸縮性,例如可以根據(jù)負(fù)載情況增加或減少節(jié)點個數(shù),可以根據(jù)業(yè)務(wù)情況劃分業(yè)務(wù)的資源分配,可以根據(jù)每臺機器的負(fù)載實現(xiàn)負(fù)載均衡,可以充分利用每個節(jié)點的資源實現(xiàn)分布計算。
最上層就是應(yīng)用的分布計算 了,應(yīng)用分布對比數(shù)據(jù)庫分布要容易得多,一般采用廉價的PC服務(wù)器就可以實現(xiàn)線形擴展。不過,在高可用的RAC及網(wǎng)格計算模式下,多個應(yīng)用在一個RAC環(huán) 境中,更有利于資源的合理分配。比如,在特定時期,可以讓財務(wù)系統(tǒng)使用更多的機器實現(xiàn)財務(wù)對賬計算,在另外一個時期,可能讓其他業(yè)務(wù)系統(tǒng)使用更多的資源計 算。
所以,理想的RAC以及網(wǎng)格計算,不需要關(guān)心數(shù)據(jù)庫是放在什么位置,數(shù)據(jù)庫是怎么運行的,只需要發(fā)出一個需求,讓網(wǎng)格返回一個結(jié)果而已,就像我們用電一樣,插上插頭,電燈就可以亮了。
Oracle備用數(shù)據(jù)庫Standby/Data Guard
Standby database/Data guard是Oracle推出的一種高可用性數(shù)據(jù)庫方案,在主節(jié)點與備用節(jié)點間通過日志同步來保證數(shù)據(jù)同步,備用節(jié)點作為主節(jié)點的備份,可以實現(xiàn)快速切換與災(zāi)難性恢復(fù)。
Oracle從7.3才開始 支持Standby database。從9i開始,發(fā)展為Data guard,并支持Maximize protection、Maximize availability、Maximize performance三種保護模式,可以實現(xiàn)自由的手工主備切換,實現(xiàn)高可用的條件。如果配置合理,可以部分實現(xiàn)自動切換。
從Oracle 9iR2開始,除了原來的物理備用數(shù)據(jù)庫(Physical Standby),也開始支持邏輯備用數(shù)據(jù)庫(Logical Standby),邏輯備用數(shù)據(jù)庫能夠?qū)崿F(xiàn)在數(shù)據(jù)同步的時候可讀寫。另外,從Oracle 11g開始,Oracle也開始推出物理備用數(shù)據(jù)庫可以在Open read only模式下實時(real time)同步日志。
提醒:如果不做特殊說明,本書中介紹的Standby都是Oracle 9i以后的Data guard環(huán)境,即使名稱叫Standby,其實也是指Data guard。
主要的技術(shù)特點:
(1)可以實現(xiàn)數(shù)據(jù)庫主機以及共享存儲的完全冗余保護,該冗余甚 至可以跨地域,做成容災(zāi)保護,是Oracle主推的容災(zāi)產(chǎn)品。在Standby中,主節(jié)點必須運行在歸檔模式下,并且可能要強制歸檔(Force Logging),以保證備用節(jié)點的數(shù)據(jù)正確性,因此,該特性在一定方面并不適合數(shù)據(jù)倉庫。
(2)Standby主備用節(jié)點對OS的環(huán)境要求比較高,一般要求是相同或者是相近的OS環(huán)境(Oracle 11g以后這個條件有所放松),而且數(shù)據(jù)庫版本也有特定的要求。如不能做Oracle 9i到Oracle 10g的Standby。
(3)除了最大保護模式外,其他模式下如果主站點的存儲損壞而導(dǎo)致備用站點進行失敗切換的時候,需要注意數(shù)據(jù)的丟失問題,務(wù)必保證當(dāng)前環(huán)境聯(lián)機日志的多重冗余保護,并且在切換之前,完全同步主站點當(dāng)前的聯(lián)機日志。
(4)在Oracle 11g以前,物理備用節(jié)點的主機與存儲基本不能提供訪問,僅僅能提供只讀查詢,所以該技術(shù)也有嚴(yán)重的資源浪費,不過該技術(shù)因為成本比較低,管理方便,技術(shù) 成熟,所以被廣泛使用。在Oracle 11g以后,物理Standby也可以在應(yīng)用日志的時候就提供只讀查詢,大大的提高了物理Standby的可用性。
(5)從Oracle 9i開始提供的邏輯Standby,可以在應(yīng)用SQL同步的時候,提供讀寫操作。但是,Oracle 9i的邏輯Standby問題比較多,Oracle 10gR2以后的邏輯Standby可以適當(dāng)使用,也是一個讀寫分離的好方法。
如圖1-15所示,備用Standby如果是邏輯 Standby,或者是Oracle 11g以后的物理Standby,則可以在應(yīng)用日志(SQL)的時候提供讀操作,做到讀寫分離。當(dāng)可讀的Standby很多時,如一個主數(shù)據(jù)庫能夠連接很 多可以提供讀操作的備用Standby,讀寫分離的效果將更明顯。
圖1-15? Standby讀寫分離
另外,在主數(shù)據(jù)庫發(fā)生故障的時候,可以選擇切換到其中一個Standby上,在做設(shè)計的時候,為了成本考慮,可以選擇一個Standby的硬件環(huán)境跟主庫相近,提供切換,另外的Standby僅僅是提供讀查詢,硬件環(huán)境也可以相對差一些,不提供切換。
為了保證Standby的更高可用性,可以將RAC與Standby結(jié)合使用,就如上面提到過的Oracle MAA體系結(jié)構(gòu),主庫與備用庫都是RAC。另外,如果需要,選擇一些單節(jié)點的機器,提供非接管性的查詢服務(wù)。
Oracle高級復(fù)制與流(Advanced Replication/Streams)
Advanced Replication/Streams 的設(shè)計目的是更靈活地實現(xiàn)數(shù)據(jù)分布,這種技術(shù)可以將一個數(shù)據(jù)庫中的表,用戶(Schema),表空間(Tablespace)或者整個數(shù)據(jù)庫復(fù)制到另一數(shù) 據(jù)庫中,甚至是雙向同步。 Advanced Replication是基于內(nèi)部觸發(fā)器的技術(shù),而Streams采用挖掘日志的方式,對主系統(tǒng)的壓力將更小。
從Oracle 9iR2開始,Oracle更傾向使用Streams的技術(shù),但是也不是說Oracle不再發(fā)展高級復(fù)制了,只不過是Streams將更適合于高可用環(huán)境 的復(fù)制。而且本書將不介紹高級復(fù)制,只介紹Streams或與其原理相同的Quest share plex/dsg realsync。
在Oracle 10g/11g中,Streams技術(shù)又得到了很大的強化和擴展,如10g以后開始DownStream、DownStream real time捕獲等,對主系統(tǒng)的影響就更小了。甚至可以通過在異地對歸檔日志/聯(lián)機日志的挖掘,在對主系統(tǒng)基本沒有任何壓力的情況下,實現(xiàn)對數(shù)據(jù)庫的表對象、 用戶、表空間甚至整個數(shù)據(jù)庫的同步。從11g起,Streams還可以支持實時的數(shù)據(jù)捕獲。
Streams主要的技術(shù)特點如下:
(1)Streams最大的特點就是靈活,可以跨平臺對單獨的表對象、用戶、表空間或者整個數(shù)據(jù)庫進行復(fù)制。而且復(fù)制的壓力更小,如在主庫之外的機器上分析日志,將對主庫沒有任何額外壓力,著名的復(fù)制軟件Share plex就是采用類似的技術(shù)進行數(shù)據(jù)復(fù)制的。
(2)Streams還能實現(xiàn)雙向復(fù)制,或者多源復(fù)制(見圖1-16),可以根據(jù)應(yīng)用的特點,自定義復(fù)制方式,這個是Standby或者其他容災(zāi)軟件所不能做到的。
(3)可以實現(xiàn)數(shù)據(jù)庫主機及共享存儲的完全冗余保護,甚至是跨地域容災(zāi)保護,在很多比較大型的在線系統(tǒng)中,如eBay購物網(wǎng)站,采用該技術(shù)(share plex)實現(xiàn)系統(tǒng)的讀寫分離,通過該技術(shù)把寫站點的數(shù)據(jù)復(fù)制到多個讀站點,大大提高系統(tǒng)的可用性、擴展性與安全性。
因為Streams在Oracle 10gR2以前,問題還比較多,導(dǎo)致該技術(shù)沒有被廣泛使用,但是其對應(yīng)軟件share plex使用還是很廣泛的,不過因為其昂貴的價格,則是需要考慮其搭建成本的。不過,Oracle 10gR2以后,Streams還是值得期待的。
圖1-16? Streams復(fù)制
如果說Standby主要用在容災(zāi)設(shè)計上,Streams則主要用于Standby所不能完成的,靈活的數(shù)據(jù)同步。它可以是:
l?????????? 跨平臺,跨版本等遷移。
l?????????? 可以靈活配置,如只同步一部分?jǐn)?shù)據(jù),甚至可以相互同步。
l?????????? 可以跨數(shù)據(jù)庫同步,如從Oracle數(shù)據(jù)庫同步到MS SQL Server數(shù)據(jù)庫。
l?????????? 兩邊的數(shù)據(jù)庫可以同時讀寫。
以上一些特點,在很大程度上,主要用來彌補Standby的一些不足,當(dāng)然,特別是Oracle 11g以后,Standby與Streams走得越來越近,但是,Streams的一些優(yōu)勢,如部分?jǐn)?shù)據(jù)同步、自定義規(guī)則的同步、多源同步等問題,Standby還實現(xiàn)不了。
主機相關(guān)HA
Oracle主機HA(Server HA)就是上面說的狹義HA,是基于OS的技術(shù),采用OS支持的Cluster Soft來保證主機的冗余保護,可以在主機錯誤、網(wǎng)絡(luò)錯誤時實現(xiàn)自動的保護切換。但是,跟RAC一樣,它使用共享存儲,所以不能保證共享存儲的高可靠性。
它的基本架構(gòu)共分兩種模式:雙機互備援(Dual Active)模式和雙機熱備份(Hot Standby)模式。對于雙機互備模式,雙機都是正常工作的,但是工作業(yè)務(wù)不同,在一個主機故障時,切換到另外一個主機上;雙機熱備模式則只有一個機器 工作,另外一個機器處于接管狀態(tài)。不過,它們的最終原理還是active/standby機制。
不管是哪種模式,Cluster軟件都可以正確檢測到系統(tǒng)異常并自動進行失敗切換,如果是雙機互備模式,則需要注意當(dāng)兩個業(yè)務(wù)都切換到一個Server上的時候,該機器是否能承載雙份的壓力。
主要的技術(shù)特點:
(1)與RAC一樣,Database 所有的數(shù)據(jù)文件(Data files)是建立在共享存儲上面的,存儲的冗余保護則需要依賴其他技術(shù),如RAID、存儲復(fù)制、卷復(fù)制等等。
(2)HA的技術(shù)簡單成熟,所以在實際使用中,也能被廣泛采用,但是,對主機資源的浪費也最為嚴(yán)重,基本上要保證有對等的資源處于等待狀態(tài)。
HA很類似于RAC,需要兩個或兩個以上的主機系統(tǒng)。 因此,在主機失敗,或者是一個主機的網(wǎng)絡(luò)失敗的情況下,都可以提供某種程度的恢復(fù),保持系統(tǒng)可用。HA與RAC最大的差別是,一個是OS 上的active/standby解決方案,一個是Oracle的提供的active/standby的解決方案:
圖1-17? 主機HA
如圖1-17所示的是一個典 型的主機HA雙機解決方案,主機采用雙機互備模式,也就是典型的active/standby方式。如果主機發(fā)生故障,業(yè)務(wù)可以自動切換到備用機上。另 外,因為共享存儲本身不提供保護功能,這里采用存儲鏡像技術(shù)復(fù)制到另外一臺存儲上面,提供數(shù)據(jù),包括在必要的時刻提供數(shù)據(jù)查詢以及存儲失敗的接管。
主機HA的最大好處就是可以 解決服務(wù)器的單點故障問題,如機器故障,與RAC一樣,它并不能解決磁盤故障問題或陣列故障問題。所以HA也必須采用附加的備份機制,如存儲同步與異步復(fù) 制技術(shù)、LV鏡像與復(fù)制技術(shù)、數(shù)據(jù)備份策略等,也可以配套使用Oracle Data guard來實現(xiàn)數(shù)據(jù)保護。
主機HA的機制起源比較早,發(fā)展到現(xiàn)在已經(jīng)日趨成熟,在實際案例中,使用還比較廣泛,但是它必須有一半的資源處于等待狀態(tài),所以資源浪費比較嚴(yán)重。
除了數(shù)據(jù)庫環(huán)境的高可用設(shè)計 外,其他的高可用設(shè)計包括Oracle數(shù)據(jù)庫高可用輔助環(huán)境設(shè)計、應(yīng)用設(shè)計、數(shù)據(jù)庫設(shè)計等方面。不過這些都不是本書的重點內(nèi)容,本書只做一些簡單的介紹, 其中,第2章會比較詳細(xì)地專門介紹高可用存儲與主機的選擇和設(shè)計,本章也會介紹一些簡單的高可用網(wǎng)絡(luò)設(shè)計知識、高可用應(yīng)用設(shè)計及高可用數(shù)據(jù)庫設(shè)計。
這里先介紹高可用的網(wǎng)絡(luò)設(shè)計,存儲與主機的高可用設(shè)計還是等到第2章介紹。可靠的網(wǎng)絡(luò)環(huán)境在高可用環(huán)境中是必不可少的,網(wǎng)絡(luò)環(huán)境主要可能考慮的是如下幾個因素:
l?????????? 可靠性,包括鏈路與硬件冗余
l?????????? 高速性,包括響應(yīng)速度與吞吐量(帶寬)
l?????????? 健壯性,比如在Dos攻擊時的表現(xiàn)
l?????????? 安全性,有很強的安全策略,防止別人侵入
如果一個網(wǎng)絡(luò)能做到以上4點,那么這個網(wǎng)絡(luò)基本可以被認(rèn)為是一個高可用的網(wǎng)絡(luò)了,復(fù)雜的網(wǎng)絡(luò)環(huán)境,還可能涉及路由規(guī)劃、DNS設(shè)置、城域或廣域的高速互連。當(dāng)然,在復(fù)雜的網(wǎng)絡(luò)環(huán)境中,很多事情需要網(wǎng)絡(luò)運營商的配合,而不是單個公司可以解決的。
1.3.1? 簡單網(wǎng)絡(luò)
一個簡單的高可用網(wǎng)絡(luò)環(huán)境,可能就分布在一個公司內(nèi)部或一個機房內(nèi)部,圖1-18是一個網(wǎng)絡(luò)運營商(或者是IDC機房)內(nèi)部的一個高可用局域網(wǎng)環(huán)境:
圖1-18? 簡單網(wǎng)絡(luò)設(shè)計
我們可以看到,這個結(jié)構(gòu)可以簡單的分為3個層次:
(1)網(wǎng)絡(luò)出口層,即最上層的出口是網(wǎng)絡(luò)運營商,如電信運營商或網(wǎng)通運營商。他們負(fù)責(zé)把內(nèi)部網(wǎng)絡(luò)的信息流和外部互聯(lián)與傳遞。
(2)核心網(wǎng)絡(luò)層,就是中間的主要網(wǎng)絡(luò)設(shè)備,如主交換機、主路由器都采用了對稱冗余的方式,在路由器與交換機之間,還存在冗余的負(fù)載均衡設(shè)備。
(3)應(yīng) 用網(wǎng)絡(luò)層,網(wǎng)絡(luò)的最下層就是內(nèi)部應(yīng)用層了,這里可能包括所有的應(yīng)用服務(wù)器與數(shù)據(jù)庫,還有一些內(nèi)部的小的網(wǎng)絡(luò)交換機與負(fù)載均衡設(shè)備。為了安全考慮,應(yīng)用可能 會根據(jù)不同的類型被分配到不同的子網(wǎng)里面去,如網(wǎng)絡(luò)Vlan,不同的Vlan之間有不同的訪問策略,這個可以通過網(wǎng)絡(luò)層的策略與ACL來完成。
1.3.2? 復(fù)雜網(wǎng)絡(luò)
如果說簡單的網(wǎng)絡(luò)一般都是一個局域網(wǎng)環(huán)境,那復(fù)雜的網(wǎng)絡(luò)一般都是城域網(wǎng)或廣域網(wǎng)絡(luò)了。在這樣的網(wǎng)絡(luò)環(huán)境中,設(shè)置將變得更復(fù)雜,不過,有一點是始終不變的,那就是冗余,沒有冗余就沒有網(wǎng)絡(luò)的高可用。
圖1-19是一個中等復(fù)雜的城域網(wǎng)絡(luò)。
圖1-19? 復(fù)雜網(wǎng)絡(luò)設(shè)計
在以上網(wǎng)絡(luò)環(huán)境中,通過一系列路由設(shè)備,把4個子網(wǎng)互聯(lián)起來,每個子網(wǎng)可以相當(dāng)于一個上面的簡單網(wǎng)絡(luò)設(shè)計中的環(huán)境。
從以上看來,網(wǎng)絡(luò)基本就是一座橋梁,連接了最終的用戶與應(yīng)用,也連接了應(yīng)用與數(shù)據(jù)。網(wǎng)絡(luò)的速度、帶寬、穩(wěn)定性、安全性也就決定了這座橋梁的高可用性。所以,骨干網(wǎng)絡(luò)的設(shè)備都是多重冗余并且是可接管的。
在更復(fù)雜的遠程網(wǎng)絡(luò)環(huán)境中,涉及的路由設(shè)備可能會更多,可靠性與安全性設(shè)計也會更復(fù)雜。
1.4.1? 高可用應(yīng)用設(shè)計技術(shù)
高可用應(yīng)用設(shè)計這幾年發(fā)展得很快,新的技術(shù)也層出不窮,但是,主要包含如下三項技術(shù),或者是這三項技術(shù)的組合:它們是分布式技術(shù)、Cache技術(shù)與Search技術(shù)。
u????????? 分布式技術(shù)
應(yīng)用服務(wù)器相對數(shù)據(jù)庫服務(wù)器來說是更廉價的,所以,應(yīng)用設(shè)計最根本的一點就是分布。應(yīng)用服務(wù)器可以采用幾百臺,幾千臺甚至 幾萬臺來做分布式計算,用戶行為與應(yīng)用服務(wù)器之間采用負(fù)載均衡設(shè)備,這樣的情況下,即使壞掉幾臺服務(wù)器,對整個應(yīng)用構(gòu)架也是沒有任何影響的。分布式技術(shù)現(xiàn) 在已經(jīng)從網(wǎng)格(grid)計算技術(shù)擴展到云(cloud)計算技術(shù),并進一步走向虛擬化。
u????????? Cache技術(shù)
除了分布,高可用應(yīng)用設(shè)計最核心的技術(shù)是Cache,所謂Cache就是高速緩存,而應(yīng)用層Cache,就是利用服務(wù)器內(nèi) 存,把數(shù)據(jù)緩存到內(nèi)存中,利用內(nèi)存的高訪問速度,提高應(yīng)用的訪問速度。當(dāng)今時代,Cache無處不在,如存儲有Cache,主機有Cache,數(shù)據(jù)庫有 Cache,應(yīng)用也有Cache。這里主要介紹的是應(yīng)用的Cache,數(shù)據(jù)庫的Cache就是上面所說到的SGA,至于其他的一些Cache方式,如存儲 Cache,本書第2章也會有詳細(xì)介紹。
Cache在內(nèi)存中的數(shù)據(jù),可以采用定時更新或者是實時更新。在定時更新中,數(shù)據(jù)同步一般有一個延遲;如果是實時(real time)更新,如被Cache的數(shù)據(jù)發(fā)生了變化,就更新Cache服務(wù)器,或者是通知Cache服務(wù)器來獲取最新的數(shù)據(jù)。
當(dāng)然,Cache也有很多變化,如分布式Cache,把分布技術(shù)與Cache技術(shù)有效結(jié)合,讓Cache數(shù)據(jù)分布在多個應(yīng)用服務(wù)器上面,而且任何一個數(shù)據(jù)可能被Cache多份。分布式Cache的最大的好處就是,如果單個機器的損壞,對整個Cache環(huán)境沒有任何影響。
Cache技術(shù)還可以擴展到內(nèi)存文件系統(tǒng)、內(nèi)存索引、內(nèi)存數(shù)據(jù)庫等不同的領(lǐng)域與方式。如分布式的內(nèi)存文件系統(tǒng),結(jié)合了文件 系統(tǒng)的優(yōu)點,又實現(xiàn)了分布與快速響應(yīng),可以快速返回文件數(shù)據(jù),如圖片文件的存放與讀取。內(nèi)存數(shù)據(jù)庫則結(jié)合了數(shù)據(jù)庫的特點與Cache的快速,如 Oracle公司的timesten內(nèi)存數(shù)據(jù)庫,既可以實現(xiàn)數(shù)據(jù)庫的事務(wù)型應(yīng)用,又可以實現(xiàn)數(shù)據(jù)的快速響應(yīng)。
u????????? Search技術(shù)
除了分布式與Cache技術(shù),現(xiàn)在還有一個發(fā)展很迅速,使用很廣泛的技術(shù),那就是Search技術(shù)。其實Search也是基于Cache的,不過,Search還有自己的很多技術(shù)特點,如Build技術(shù),分詞技術(shù)等等。
一般的Build技術(shù)采用定時Build,因為在數(shù)據(jù)量非常巨大的情況下,很難做到實時(real time)的Build。如Google、Baidu基本上都是每天定時更新一次數(shù)據(jù),所以,在更新以前,怎么搜索都是相同的結(jié)果。當(dāng)然,在一些特定的情 況下,也需要采用實時Build,如電子商務(wù)網(wǎng)站eBay,希望每個商品的改變都能立即顯示出來。實時Build會要求每個改變都能立即通知到Build 服務(wù)器,然后同步到Search的特定內(nèi)存索引上。
1.4.2? 典型應(yīng)用構(gòu)架結(jié)構(gòu)
因為以上的幾項技術(shù)并不是單獨存在的,而且,不同的應(yīng)用可能在不同的層次上,我們可以對應(yīng)用做一個簡單的層次模型(如圖1-20)來觀察這些技術(shù)。
圖1-20? 應(yīng)用設(shè)計
在典型的應(yīng)用設(shè)計體系結(jié)構(gòu)圖中,可以分為3個層次,每個層次之間還可分為多個子層。層次之內(nèi)的模塊是獨立的,沒有業(yè)務(wù)關(guān)聯(lián)關(guān)系,但是,層次之間存在一定的交互關(guān)系。
(1)用戶層,代表了用戶的所有請求,以及活動行為。
(2)應(yīng)用層,首先是包括各種各樣的產(chǎn)品與功能,如交易系統(tǒng)、財務(wù)系統(tǒng)等,然后通過下??????? 層的各種核心服務(wù),如一些公共通用性服務(wù)接口,直接訪問下層數(shù)據(jù),為搜索引擎提供數(shù)據(jù)等。
在核心的服務(wù)之下,就是應(yīng)用服務(wù)接口API,這些代用業(yè)務(wù)性質(zhì)的API可以被上層的服務(wù)直接調(diào)用,也可以開放給外部客戶,供他們訪問。在應(yīng)用服務(wù)接口API之下,就是應(yīng)用層的分布式Cache,提供被訪問數(shù)據(jù)的緩沖。
(3)數(shù)據(jù)層,從應(yīng)用服務(wù)接口API訪問的數(shù)據(jù),可能直接被應(yīng)用層的Cache返回,直接返回的叫Cache命中,如果不能命中的,則需要從數(shù)據(jù)庫,或者是從文件系統(tǒng)上返回。數(shù)據(jù)庫與文件系統(tǒng)也可能是分布式的,通過數(shù)據(jù)調(diào)用接口API統(tǒng)一控制。
數(shù)據(jù)調(diào)用接口API中,主要包括路由技術(shù)與隊列技術(shù)。
路由技術(shù)則是封裝了數(shù)據(jù)庫的位置,甚至是數(shù)據(jù)庫的類型,如有兩個不同的數(shù)據(jù)庫,Oracle與Mysql,甚至是Oracle與文件系統(tǒng),它們分布在不同的物理位置,但是路由技術(shù)知道從什么位置、什么數(shù)據(jù)庫中獲得必要的數(shù)據(jù),而不需要應(yīng)用層來關(guān)心。
隊列技術(shù)則是一種同步技術(shù),如分布式的數(shù)據(jù)庫中,經(jīng)常有一個事務(wù)需要跨數(shù)據(jù)庫來運行,這種情況下,可以先寫隊列,由隊列同步到不同的數(shù)據(jù)庫中。
在上面介紹了很多Oracle數(shù)據(jù)庫的高可用產(chǎn)品,它們也是數(shù)據(jù)庫設(shè)計中非常重要的一個環(huán)節(jié)。雖然它們是本書的重點,也是保證Oracle高可用環(huán)境的不可缺少的部分,但是,除了這些,另外也還需要考慮一下數(shù)據(jù)庫的應(yīng)用設(shè)計或者是叫Schema設(shè)計。
數(shù)據(jù)庫的Schema設(shè)計的時候,也是需要有豐富的設(shè)計經(jīng)驗,才可以設(shè)計出來一個高效的高可用數(shù)據(jù)庫的。好的數(shù)據(jù)庫設(shè)計,可以保證數(shù)據(jù)庫的可擴充性與良好的性能。下面就范式設(shè)計、反范式設(shè)計與數(shù)據(jù)庫分布設(shè)計說一下數(shù)據(jù)庫Schema設(shè)計。
1.5.1? 數(shù)據(jù)庫范式設(shè)計
對于數(shù)據(jù)庫范式設(shè)計,一般在設(shè)計時,只需要了解到第三范式即可,后面的范式?jīng)]有必要過于計較,前三種范式在數(shù)據(jù)庫設(shè)計中還是非常重要的。
u????????? 第一范式(1NF):在關(guān)系模式R中的每一種具體關(guān)系r中,如果每個屬性值都是不可再分的最小數(shù)據(jù)單位,則稱R是第一范式的關(guān)系。
第一范式簡單的說,就是要求屬性具有原子性,不可再分解。表1-1是一個最簡單的例子。
表1-1
編號 姓名 選修科目 001 張三 語文,數(shù)學(xué),英語 002 李四 物理,化學(xué) 003 王五 歷史,地理,生物
從表中可以看到,在課程選修表中,選修科目設(shè)計為一個字段,選修的科目內(nèi)容用逗號分開,看起來是好像沒有什么問題,但是,如果想統(tǒng)計哪些人選修了哪門科,將變得非常困難,如想統(tǒng)計哪些人選修了化學(xué),可能需要用到如下的SQL
SQL>select count(*) from course where subject like ‘%化學(xué)%’;
除了這個影響,更新的影響也非常大,如,上面的李四現(xiàn)在想在選修科目中增加一門生物,他必須先讀出以前的科目,然后在科目后面合并一個生物,這個表就不滿足第一范式。
那么,為了滿足第一范式,可以做一點簡單的修改(見表1-2)。
表1-2
編號 姓名 選修科目 001 張三 語文 001 張三 數(shù)學(xué) 001 張三 英語 002 李四 物理 002 李四 化學(xué) 003 王五 歷史 003 王五 地理 003 王五 生物
作了以上修改就可以滿足第一范式了,如果想統(tǒng)計哪些人選修了化學(xué),SQL語句可以修改為。
SQL>select count(*) from course where subject = ‘化學(xué)’
如果想給李四增加一門生物選修課,只要insert一個新行即可。
u?????? 第二范式(2NF):如果關(guān)系模式R(U,F)中的所有非主屬性都完全依賴于任意一個候選關(guān)鍵字,則稱關(guān)系R是屬于第二范式的。
第二范式簡單地說,就是每個表有個主鍵,其他字段完全依賴于該主鍵。
還是以上面的表為例,現(xiàn)在滿足了第一范式,但是,不滿足第二范式,也就是沒有可以唯一確定的主鍵,如果王五同學(xué)想把課程地理修改成天文學(xué),他不得不把所有的字段作為查詢條件來更新該記錄。那好,我們增加一個主鍵ID(PK),如表1-3所示:
表1-3
ID(PK) 編號 姓名 選修科目 1 001 張三 語文 2 001 張三 數(shù)學(xué) 3 001 張三 英語 4 002 李四 物理 5 002 李四 化學(xué) 6 003 王五 歷史 7 003 王五 地理 8 003 王五 生物
有了主鍵,如果能確定哪一行需要修改,用主鍵就可以定位該行。如王五同學(xué)想把課程地理修改成天文學(xué),那么更新語句可以是根據(jù)主鍵來更新。
SQL>update course set subject = ‘天文學(xué)’ where id=7;
這樣,以上的表符合第二范式了嗎,其實還沒有,我們可以看到,編號依賴于ID,但是姓名是依賴于編號的,沒有唯一的主鍵,還不符合第二范式,那會有什么問題呢?如張三要換一個名字,就要更改這個表中的三條記錄,如果涉及1萬條記錄呢,那就需要更新1萬條記錄。
這也僅僅是其中一個問題,還有,假如要統(tǒng)計有多少個學(xué)生,從課程表中是很難獲得的,因為可能有的學(xué)生沒有選修課程,就是全部選修了,也要distinct,大大影響了性能。
基于以上很多影響,可以修改為如表1-4和表1-5的父子表:
表1-4為父表——學(xué)生表,表1-5為子表——課程表。
表1-4
編號(PK) 姓名 來源地 001 張三 北京 002 李四 上海 003 王五 廣州
表1-5
ID(PK) 學(xué)生編號(FK) 選修科目 1 001 語文 2 001 數(shù)學(xué) 3 001 英語 4 002 物理 5 002 化學(xué) 6 003 歷史 7 003 地理 8 003 生物
有了上面的兩張表,現(xiàn)在,清晰多了,學(xué)生信息直接從學(xué)生表中獲得,課程信息直接從課程表中獲得。
u????????? 第三范式(3NF):如果關(guān)系模式R(U,F)中的所有非主屬性對任何候選關(guān)鍵字都不存在傳遞信賴,則稱關(guān)系R是屬于第三范式的。
第三范式是很重要的,表示了不要存在值的依賴關(guān)系,比如還是上面的課程表,現(xiàn)在增加了選修課成績等級(見表1-6)。
表1-6
ID(PK) 編號 選修科目 成績 等級 1 001 語文 60 及格 2 001 數(shù)學(xué) 87 良好 3 001 英語 57 不及格 4 002 物理 43 不及格 5 002 化學(xué) 99 優(yōu)秀 6 003 歷史 90 優(yōu)秀 7 003 地理 74 及格 8 003 生物 81 良好
這里,相信大家都能看出來問題在哪里,因為等級是直接依賴于成績的值的,現(xiàn)在假定某個人的成績從60修改成50,那么不得不修改對應(yīng)的等級,如果修改失誤,則可能造成數(shù)據(jù)的異常(不對應(yīng)),這就不符合第三范式。
除了上述3種范式,還有很多其他范式,這里不再一一列舉,這三種范式比較重要,所以,在這里列了出來,供大家在設(shè)計數(shù)據(jù)庫的時候參考。
注意:數(shù)據(jù)庫的設(shè)計的好壞,將可能影響到應(yīng)用的性能,數(shù)據(jù)庫設(shè)計得好,可以為高可用的環(huán)境打下良好的根基。
1.5.2? 反范式數(shù)據(jù)庫設(shè)計
數(shù)據(jù)庫設(shè)計要嚴(yán)格遵守范式,這樣設(shè)計出來的數(shù)據(jù)庫,雖然思路很清晰,結(jié)構(gòu)也很合理,但是,有的時候,卻要在一定程度上打破范式設(shè)計。
這里其實并不矛盾,因為范式越高,設(shè)計出來的表可能越多,關(guān)系可能越復(fù)雜,但是性能卻不一定會很好,因為表一多,就增加了關(guān)聯(lián)性。特別是在高可用的OLTP數(shù)據(jù)庫中,這一點表現(xiàn)得很明顯。
最明顯的打破范式的設(shè)計方法就是冗余法,以空間換取時間的做法,把數(shù)據(jù)冗余在多個表中,當(dāng)查詢時可以減少或者是避免表之間的關(guān)聯(lián)。
還是用上面的例子,學(xué)生表與課程表,假定課程表要經(jīng)常被查詢,而且在查詢中要顯示學(xué)生的姓名,查詢語句則為:
SQL>select code,name,subject from course c,student s where s.id=c.code where code=?
這個語句如果被大范圍、高頻率執(zhí)行,可能會因為表關(guān)聯(lián)造成一定程度的影響,現(xiàn)在,假定評估到學(xué)生改名的需求是非常少的,那么,就可以把學(xué)生姓名冗余到課程表中,又變回了如表1-7所示:
表1-7
ID(PK) 編號 姓名 選修科目 1 001 張三 語文 2 001 張三 數(shù)學(xué) 3 001 張三 英語 4 002 李四 物理 5 002 李四 化學(xué) 6 003 王五 歷史 7 003 王五 地理 8 003 王五 生物
注意:我這里并沒有省略學(xué)生表,不過是把學(xué)生姓名冗余在了課程表中,如果萬一有很少的改名需求,只要保證在課程表中改名正確即可。
那么,修改以后的語句可以簡化為:
SQL>select code,name,subject from course c where code=?
1.5.3? 數(shù)據(jù)庫分布技術(shù)
除了應(yīng)用更容易采用分布式技術(shù)以外,數(shù)據(jù)庫也是可以采用分布技術(shù)的,而且是有必要采用分布式技術(shù)的,特別是訪問量很高的應(yīng)用,如果不采用分布技術(shù),再高配置的服務(wù)器也可能承載不了業(yè)務(wù)的需求。
數(shù)據(jù)庫的分布技術(shù),大致可以分為如下幾類:
u????????? 主機角度的分布技術(shù)
數(shù)據(jù)庫的分布技術(shù),主要是為了解決單個數(shù)據(jù)庫服務(wù)器成為瓶頸,而不能承載業(yè)務(wù)的情況。這時,只要把數(shù)據(jù)庫運行在多個主機上即可,Oracle RAC或者是網(wǎng)格計算就是一種很好的解決方案,它們可以保證在多個主機上運行數(shù)據(jù)庫業(yè)務(wù)。
另外,讀寫分離也是一種 有效的解決方案,讀寫分離就是在一個數(shù)據(jù)庫中寫入數(shù)據(jù),然后把寫入的數(shù)據(jù)同步到多個站點,在其他的站點上讀取數(shù)據(jù),這樣也可以把應(yīng)用的負(fù)載分布在多個不同 的數(shù)據(jù)庫站點上面。如果寫的數(shù)據(jù)庫失敗,可以找一個讀的數(shù)據(jù)庫來接管,從Oracle技術(shù)角度來說,Logical standby、Streams、Oracle 11g的可只讀Physical standby都可以實現(xiàn)這樣的需求;從非Oracle技術(shù)角度來說,復(fù)制軟件如quest share plex/dsg realsync也可以實現(xiàn)這樣的需求。
u????????? 應(yīng)用角度的分布技術(shù)
數(shù)據(jù)庫也可以從應(yīng)用的角度考慮分布,從應(yīng)用角度的分布一般有兩種解決方案,垂直分割與水平分割技術(shù)(見圖1-20)。
垂直分割,表示按照應(yīng)用來分割,如應(yīng)用1與應(yīng)用2是可以獨立出來的完全不同的應(yīng)用,則把它獨立出來,分割在兩個不同的數(shù)據(jù)庫服務(wù)器上,這樣就實現(xiàn)了垂直分割。這種情況下,如果一個應(yīng)用故障,就不會影響到其他應(yīng)用。
水平分割,一般是數(shù)據(jù)量 的分割,如有一個用戶表,可以按照一定規(guī)則,把用戶表分割成兩個表,再分布在兩個不同的數(shù)據(jù)庫中,當(dāng)特定的用戶訪問數(shù)據(jù)庫的時候,根據(jù)規(guī)則就可以知道它在 哪個數(shù)據(jù)庫中,然后訪問該數(shù)據(jù)庫即可。這種情況下,如果一個庫失效,受影響的只是這個庫存放的特定的用戶。
圖1-21? 數(shù)據(jù)庫分布技術(shù)
如圖1-21,拿兩個最簡單的應(yīng)用做比較,在垂直分割技術(shù)中,論壇與博客是兩個不同的數(shù)據(jù)庫,論壇訪問論壇的數(shù)據(jù)庫,博客訪問博客的數(shù)據(jù)庫。這種情況下,如果論壇壞了,不會影響博客,反之亦然。所以,這種方式,影響的是一個特定的應(yīng)用。
另外一種分割技術(shù)中,把一半用戶的論壇與博客數(shù)據(jù)存放在一個數(shù)據(jù)庫,另外一半存入另外一個數(shù)據(jù)庫,兩個庫基本一樣,都是保 存接近1/2的論壇+博客數(shù)據(jù)。這種情況下,如果一個庫壞了,就有一半的用戶不能訪問論壇,也不能訪問博客,而另外一半用戶是正常的。這種分法不一定是分 成2個數(shù)據(jù)庫,也可以水平分割成n個數(shù)據(jù)庫,如果出現(xiàn)問題,影響的是部分的用戶群,如1/n的用戶。
其實,在很多情況下,也不完全是單純的垂直分割或者是水平分割,而往往是混合型分割,如先根據(jù)業(yè)務(wù)來垂直分割數(shù)據(jù)庫,如果 單個業(yè)務(wù)在單個數(shù)據(jù)庫中都不能承載,則可以考慮對這個應(yīng)用再水平分割,把這個應(yīng)用分割成多個數(shù)據(jù)庫。然后,再結(jié)合RAC技術(shù)以及讀寫分離技術(shù)實現(xiàn)數(shù)據(jù)庫的 可擴展性與高可用性。
1.5.4? 區(qū)別OLTP還是OLAP
在數(shù)據(jù)庫的設(shè)計中,就算完全掌握了以上的方法,但是,在不同的數(shù)據(jù)庫類型上,使用起來也是大有差別的,這就需要設(shè)計者弄清 楚自己的業(yè)務(wù)類型。如果沒有正確地識別自己的業(yè)務(wù)類型,就盲目地開始設(shè)計數(shù)據(jù)庫,或者是盲目地尋求優(yōu)化方法,則往往是把OLAP的方法使用在OLTP上, 或者是把OLTP的方法使用在OLAP上。如果這樣,很可能會適得其反。
u????????? 什么是OLTP
OLTP,也叫聯(lián)機事務(wù)處理(Online Transaction Processing),表示事務(wù)性非常高的系統(tǒng),一般都是高可用的在線系統(tǒng),以小的事務(wù)以及小的查詢?yōu)橹?#xff0c;評估其系統(tǒng)的時候,一般看其每秒執(zhí)行的 Transaction以及Execute SQL的數(shù)量。在這樣的系統(tǒng)中,單個數(shù)據(jù)庫每秒處理的Transaction往往超過幾百個,或者是幾千個,Select 語句的執(zhí)行量每秒幾千甚至幾萬個。典型的OLTP系統(tǒng)有電子商務(wù)系統(tǒng)、銀行、證券等,如美國eBay的業(yè)務(wù)數(shù)據(jù)庫,就是很典型的OLTP數(shù)據(jù)庫。
注意:如果不特殊指定,本書中的高可用數(shù)據(jù)庫都是指OLTP類型的數(shù)據(jù)庫。
OLTP系統(tǒng)最容易出現(xiàn)瓶頸的地方就是CPU與磁盤子系統(tǒng)。
CPU出現(xiàn)瓶頸常表現(xiàn)在邏輯讀總量與計算性函數(shù)或者是過程上,邏輯讀總量等于單個語句的邏輯讀乘以執(zhí)行次數(shù),如果單個語句 執(zhí)行速度雖然很快,但是執(zhí)行次數(shù)非常多,那么,也可能會導(dǎo)致很大的邏輯讀總量。設(shè)計的方法與優(yōu)化的方法就是減少單個語句的邏輯讀,或者是減少它們的執(zhí)行次 數(shù)。另外,一些計算型的函數(shù),如自定義函數(shù)、decode等的頻繁使用,也會消耗大量的CPU時間,造成系統(tǒng)的負(fù)載升高,正確的設(shè)計方法或者是優(yōu)化方法, 需要盡量避免計算過程,如保存計算結(jié)果到統(tǒng)計表就是一個好的方法。關(guān)于邏輯讀與CPU處理能力的詳細(xì)計算方法,在第12章還有詳細(xì)介紹。
磁盤子系統(tǒng)在OLTP環(huán)境中,它的承載能力一般取決于它的IOPS處理能力,關(guān)于IOPS,在第2章中有詳細(xì)介紹。因為在 OLTP環(huán)境中,磁盤物理讀一般都是db file sequential read,也就是單塊讀,但是這個讀的次數(shù)非常頻繁。如果頻繁到磁盤子系統(tǒng)都不能承載其IOPS的時候,就會出現(xiàn)大的性能問題。另外,在第2章中,還會詳 細(xì)介紹存儲子系統(tǒng)的IOPS承載力的計算問題。
OLTP比較常用的設(shè)計與優(yōu)化方式為Cache技術(shù)與B-tree索引技術(shù),Cache決定了很多語句不需要從磁盤子系統(tǒng) 獲得數(shù)據(jù),所以,Web cache與Oracle data buffer對OLTP系統(tǒng)是很重要的。另外,在索引使用方面,語句越簡單越好,這樣執(zhí)行計劃也穩(wěn)定,而且一定要使用綁定變量,減少語句解析,盡量減少表 關(guān)聯(lián),盡量減少分布式事務(wù),基本不使用分區(qū)技術(shù)、MV技術(shù)、并行技術(shù)及位圖索引。因為并發(fā)量很高,批量更新時要分批快速提交,以避免阻塞的發(fā)生。
u????????? 什么是OLAP
OLAP,也叫聯(lián)機分析處理(Online Analytical Processing)系統(tǒng),有的時候也叫DSS決策支持系統(tǒng),就是我們說的數(shù)據(jù)倉庫。在這樣的系統(tǒng)中,語句的執(zhí)行量不是考核標(biāo)準(zhǔn),因為一條語句的執(zhí)行時 間可能會非常長,讀取的數(shù)據(jù)也非常多。所以,在這樣的系統(tǒng)中,考核的標(biāo)準(zhǔn)往往是磁盤子系統(tǒng)的吞吐量(帶寬),如能達到多少MB/s的流量。
磁盤子系統(tǒng)的吞吐量則往往取決于磁盤的個數(shù),這個時候,Cache基本是沒有效果的,數(shù)據(jù)庫的讀寫類型基本上是db file scattered read與direct path read/write。應(yīng)盡量采用個數(shù)比較多的磁盤以及比較大的帶寬,如4Gb的光纖接口。關(guān)于磁盤子系統(tǒng)的帶寬承載量計算,在第2章也將有詳細(xì)介紹。
在OLAP系統(tǒng)中,常使用分區(qū)技術(shù)、并行技術(shù)。如分區(qū)技術(shù)可以使得一些大表的掃描變得很快(只掃描單個分區(qū)),而且方便管 理。另外,如果分區(qū)結(jié)合并行的話,也可以使得整個表的掃描會變得很快。并行技術(shù)除了與分區(qū)技術(shù)結(jié)合外,在Oracle 10g中,與RAC結(jié)合實現(xiàn)多節(jié)點的同時掃描,效果也非常不錯,可把一個任務(wù),如select的全表掃描,平均地分派到多個RAC的節(jié)點上去。
在OLAP系統(tǒng)中,不需要使用綁定(BIND)變量,因為整個系統(tǒng)的執(zhí)行量很小,分析時間對于執(zhí)行時間來說,可以忽略,而 且可避免出現(xiàn)錯誤的執(zhí)行計劃。但是OLAP中可以大量使用位圖索引,物化視圖,對于大的事務(wù),盡量尋求速度上的優(yōu)化,沒有必要像OLTP要求快速提交,甚 至要刻意減慢執(zhí)行的速度。
u????????? 分開設(shè)計與優(yōu)化
以上描述了OLTP與OLAP的特點,在設(shè)計上要特別注意,如在高可用的OLTP環(huán)境中,不要盲目地把OLAP的技術(shù)拿過 來用。如分區(qū)技術(shù),假設(shè)不是大范圍地使用分區(qū)關(guān)鍵字,而采用其它的字段作為where條件,那么,如果是本地索引,將不得不掃描多個索引,而性能變得更為 低下。如果是全局索引,又失去分區(qū)的意義。
并行技術(shù)也是如此,一般在完成大型任務(wù)時才使用,如在實際生活中,翻譯一本書,可以先安排多個人,每個人翻譯不同的章節(jié), 這樣可以提高翻譯速度。如果只是翻譯一頁書,也去分配不同的人翻譯不同的行,再組合起來,就沒必要了,因為在分配工作的時間里,一個人或許早就翻譯完了。
位圖索引也是一樣,如果用在OLTP環(huán)境中,很容易造成阻塞與死鎖。但是,在OLAP環(huán)境中,可能會因為其特有的特性,提 高OLAP的查詢速度。MV也是基本一樣,包括觸發(fā)器等,在DML頻繁的OLTP系統(tǒng)上,很容易成為瓶頸,甚至是Library Cache等待,而在OLAP環(huán)境上,則可能會因為使用恰當(dāng)而提高查詢速度。
1.6.1? 美國eBay高可用環(huán)境分析
eBay(
www.ebay.com )是世界上最大的C2C電子商務(wù)網(wǎng)站,到2007年年底,該網(wǎng)站的注冊用戶數(shù)量達到2.48億,并存有10億張以上的圖片,該網(wǎng)站每天要支撐10億次的PV,有合計2P(1P=1024T)的數(shù)據(jù)量,這么龐大的一個系統(tǒng),還能整體上保證99.94%以上的高可用性。
那么,eBay是怎樣保證這么大的系統(tǒng),還有這么高訪問量的高可用呢,這里先看看他們的規(guī)模與高可用構(gòu)架結(jié)構(gòu)(見圖1-22)。
l?????????? 為了支撐這么多的業(yè)務(wù)量,有16000臺以上的Web服務(wù)器,運行J2EE,以及1000臺以上的邏輯數(shù)據(jù)庫分布在400個不同的物理主機上,實現(xiàn)了良好的水平擴展性,每天的SQL執(zhí)行量超過了440億次。
l?????????? 數(shù)據(jù)庫運行在Oracle上,應(yīng)用服務(wù)器采用websphere。每個數(shù)據(jù)庫至少有3個在線的備份,分布在8個不同的數(shù)據(jù)中心。數(shù)據(jù)庫中沒有存儲過程,只 有少量的觸發(fā)器,把很多 CPU密集型的任務(wù)從數(shù)據(jù)庫遷移到Web服務(wù)器上,因為數(shù)據(jù)庫更容易成為瓶頸,而Web服務(wù)器是廉價可擴展的。數(shù)據(jù)庫采用多點復(fù)制,可負(fù)載均衡,不采用分 布式事務(wù)。
l?????????? 應(yīng)用構(gòu)架方面,采用連接池,應(yīng)用層采用多層結(jié)構(gòu)。eBay最大的成功在于解決了兩個關(guān)鍵性的技術(shù):分布式的數(shù)據(jù)庫與實時的Search。
圖1-22? EBay高可用體系結(jié)構(gòu)
可以看到,eBay最核心的技術(shù)就是分布,首先Web服務(wù)器是分布的,存在16000臺以上的Web服務(wù)器,相對于比較集中的數(shù)據(jù)庫來說,Web服務(wù)器更容易擴展。為了保證數(shù)據(jù)庫的負(fù)載最小,eBay采用了很多策略,把負(fù)載從數(shù)據(jù)庫轉(zhuǎn)移到可擴展的Web服務(wù)器上。
在數(shù)據(jù)庫上面,eBay是先把數(shù)據(jù)庫按照應(yīng)用在一定程度上垂直分割,然后采用sheard plex水平分割,實現(xiàn)讀寫分離的分布策略。數(shù)據(jù)庫分布在多個數(shù)據(jù)中心,應(yīng)用通過數(shù)據(jù)層與負(fù)載均衡設(shè)備訪問數(shù)據(jù)庫,根本不必要關(guān)心數(shù)據(jù)庫的位置在哪里。
另外,因為數(shù)據(jù)分布在多個數(shù)據(jù)中心,而這些數(shù)據(jù)中心并不在一個地點,也就實現(xiàn)了數(shù)據(jù)的容災(zāi)保護。當(dāng)寫站點發(fā)生故障的時候,只要切換到其他一個備用站點即可。
1.6.2? Myspace構(gòu)架分析
上面分析了eBay的案例,再來看另外一個案例,那就是Myspace(
www.myspace.com ),從目前的情況來看,Myspace的月訪問量超過400億,并超越了YAHOO。
Myspace采用的是Ms SQL Server,但是,能做到這么好的性能與訪問量,是很不容易的,這里分析一下它的高可用發(fā)展歷程。
u????????? 讀寫分離分布技術(shù)
Myspace最初只有兩臺老式的Web服務(wù)器與一個Dell 雙CPU,4GB內(nèi)存的PC Server數(shù)據(jù)庫服務(wù)器,數(shù)據(jù)庫是SQL Server。當(dāng)2004年Myspace有50萬用戶的時候,數(shù)據(jù)庫服務(wù)器實在不能滿足當(dāng)時的需求,Myspace采用3臺SQL Server服務(wù)器,一個為主,所有的數(shù)據(jù)都向它提交,再由它復(fù)制到另外兩個數(shù)據(jù)庫上,實現(xiàn)了最簡單的讀寫分離。
u????????? 垂直分割技術(shù)
在2004中,Myspace用戶達到1~2百萬,存儲成為當(dāng)時最大的瓶頸,因為IO的響應(yīng)時間過長,導(dǎo)致用戶無法完成自 己的請求。這個時候,Myspace對數(shù)據(jù)庫采用垂直分割的技術(shù),不同的數(shù)據(jù)庫運行不同的業(yè)務(wù),存儲也采用了SAN存儲網(wǎng)絡(luò)技術(shù),提高了系統(tǒng)的性能與可靠 性。
u????????? 水平分割技術(shù)
在用戶越來越多的情況下,當(dāng)用戶繼續(xù)增加到3百萬后,采用以上垂直分割的技術(shù)也出現(xiàn)了問題,如一項單獨的業(yè)務(wù)在一個數(shù)據(jù)庫 中都可能成為瓶頸。最初為了適應(yīng)單個業(yè)務(wù)的增長,Myspace采用了更好的機器,但是,更好的機器并不能解決數(shù)據(jù)量增長問題,馬上又達到新的瓶頸。這個 時候,Myspace采用了分布計算與水平分割技術(shù),按照用戶進行水平分割,一個數(shù)據(jù)庫大致保存200萬個左右的用戶以及對應(yīng)用戶信息。
u????????? 虛擬化技術(shù)與Cache技術(shù)
水平分割解決了數(shù)據(jù)庫主機的問題,但是,有些特定數(shù)據(jù)庫上的用戶可能數(shù)據(jù)量特別巨大,但是有些數(shù)據(jù)庫上的用戶數(shù)據(jù)量可能又 很小,導(dǎo)致存儲設(shè)備使用嚴(yán)重不均衡。這個時候,Myspace采用了3PARdata的虛擬化存儲技術(shù),讓存儲設(shè)備統(tǒng)一管理,這樣整個SAN被當(dāng)作一個巨 大的存儲池,不再要求某個特定的存儲設(shè)備為特定應(yīng)用服務(wù)。
當(dāng)用戶越來越多,壓力越來越大,Myspace啟用了新的策略以減輕存儲系統(tǒng)的壓力,增加數(shù)據(jù)緩存層——位于Web服務(wù)器 和數(shù)據(jù)庫服務(wù)器之間,其在內(nèi)存中建立被頻繁訪問的數(shù)據(jù)副本,以前100個用戶查詢同一數(shù)據(jù),需要查詢數(shù)據(jù)庫100次,現(xiàn)在只需要1次。如果頁面變化,緩存 中的數(shù)據(jù)將從內(nèi)存中擦除,然后重新從數(shù)據(jù)庫獲取。
現(xiàn)在,Myspace已經(jīng)超過2600萬用戶,設(shè)備已升級到SQL Server 2005版,因為可以支持64位系統(tǒng),這樣可以支持更大的內(nèi)存,2006年后每臺機器的標(biāo)準(zhǔn)配置是64GB內(nèi)存。
從以上的情況來看,Myspace采用了高可用環(huán)境中的必需的幾項技術(shù):
首先就是分布式計算架構(gòu),包括應(yīng)用與數(shù)據(jù)庫,先是簡單的讀寫分離,當(dāng)讀寫分離不能適應(yīng)需要的時候,采用了垂直分割技術(shù),當(dāng)垂直分割技術(shù)也不能適應(yīng)需要的時候,最后采用了按照用戶水平分割的技術(shù)。
然后,當(dāng)存儲過于分散的時候,存儲系統(tǒng)出現(xiàn)了空間與負(fù)載使用的不均衡,他們又采取了虛擬存儲的策略,把所有的存儲整合成一個存儲池,解決了存儲設(shè)備使用不均勻的問題。
最后,當(dāng)分布技術(shù)與虛擬存儲也解決不了問題的時候,Myspace采用了Cache技術(shù),這個才是它最終能承載那么大流量的關(guān)鍵,Cache技術(shù)可以快速地響應(yīng)請求,大大地減少數(shù)據(jù)庫壓力。
本章的內(nèi)容比較多,作為全書的一個導(dǎo)讀,先介紹了Oracle的體系結(jié)構(gòu),包括內(nèi)存結(jié)構(gòu)、后臺進程、物理對象與邏輯對象。
然后,介紹了Oracle的最高體系結(jié)構(gòu)(MAA)與Oracle的典型高可用產(chǎn)品,為本書后面進一步介紹這些特性打下基礎(chǔ)。
接下來,介紹了設(shè)計高可用性數(shù)據(jù)庫的一些要點,如應(yīng)用設(shè)計、網(wǎng)絡(luò)設(shè)計、數(shù)據(jù)庫設(shè)計等,并描述了在不同的數(shù)據(jù)庫模式下,不同的設(shè)計方法。
最后,通過兩個案例描述了典型的高可用設(shè)計的方法,讀者或設(shè)計者可以根據(jù)這些設(shè)計方法或者是案例,得到一些設(shè)計自己所需要的高可用體系的啟發(fā)。
光看本章,可能得到一些啟發(fā)性的東西,但是具體的技術(shù)實現(xiàn),則需要通過后面的章節(jié)來了解。
總結(jié)
以上是生活随笔 為你收集整理的构建Oracle高可用环境HA rac:企业级高可用数据库架构、实战与经验总结 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。