2021年10月1日 星期五

11.1 冷備份與熱備份

Oracle 資料庫的備份方式可以分為兩類,冷備份與熱備份,冷備份指的是在資料庫完全靜止的狀態之下進行備份;而熱備份則是在資料庫處於運行的狀態之下進行備份。


Oracle 資料庫是由 Control File 、 Data File … 等檔案所構成,所以資料庫備份就是針對這些檔案來做備份,使用冷備份必須把資料庫 shutdown ,讓資料庫完全處於靜止的狀態,然後把 Control File 、 Data File … 等檔案複製起來做一個備份,結束後再重新將資料庫 startup ,這樣一個過程就完成了冷備份。

SQL> shutdown immediate

SQL> exit;

$ cp /u01/oradata/* /u01/orabak

$ sqlplus / as sysdba

SQL> startup


使用冷備份的資料庫還原,只需要把複製出來的備份檔案再 copy 回來,這樣就完成了資料庫還原的動作,這邊要注意的是,由於冷備份是在資料庫完全處於靜止的狀態之下將所有檔案複製出來,因此還原的時候必須把所有檔案一起複製回來,不能只單獨還原某一個檔案。


在某種程度上,使用 export (Datapump) 的方式將資料進行備份,也屬於冷備份的一種,雖然執行 export 的時候資料庫無須 shutdown ,但 export 出來的資料是當下做 export 那個時間點的資料,並不會包括後續的資料異動,例如在每日的 02:00 進行 export 的動作,如果早上 10:00 資料庫有異狀需要進行還原,那麼 import 回來也只有 02:00 那個時間點的資料, 02:00 ~ 10:00 中間的異動等於就遺失了。


熱備份是在資料庫運行的狀態之下進行備份,資料庫必須是使用 archive log 模式才能夠使用熱備份,藉由 archive log 不僅可以讓資料庫在運行的狀態之下進行備份,而資料庫還原的時候更可以讓資料庫還原到最接近現在的時間點,減少中間資料的遺失。熱備份同樣也是把資料庫的檔案複製備份出來,只是在資料庫運行的當下必須先使用 alter database begin backup 指令,然後再複製檔案,複製結束後再使用 alter database end backup ,這樣就完成了一個熱備份。

SQL> alter database begin backup;

SQL> !cp /u01/oradata/* /u01/orabak

SQL> alter database end backup;


熱備份的原理是在執行 begin backup 的當下,資料庫會暫時把 Data File 的 SCN 凍結起來不再更新,雖然凍結了 SCN 但不會影響到資料庫的運行,這時間所發生的交易都會保存在 archive log 當中,當備份結束後執行了 end backup ,此時資料庫會 apply 這中間所產生的 archive log ,讓 Data File 的 SCN 更新到目前的時間點。由於 archive log 在熱備份當中扮演了重要的角色,因此在備份檔案的時候不要忘了將 archive log 複製備份起來。


使用熱備份的還原,同樣的是把備份的檔案 copy 回來,與冷備份不同的是,將熱備份的檔案 copy 回來之後,可以再使用 archive log 將資料庫還原到最接近現在的時間點,將資料庫開啟到 mount 狀態,使用 recover database until cancel using backup controlfile開始 apply archive log :

SQL> !cp /u01/orabak/* /u01/oradata

SQL> startup mount

SQL> recover database until cancel using backup controlfile;


執行了 recover 之後,系統會提示所需要的 archive log 序號以及檔案:


系統會顯示 archive log 的檔案位置,如果位置正確的話,可以使用 AUTO 讓資料庫自行 apply 所有需要的 archive log ,如果路徑不正確的話,也可以自行提供 archive log 檔案的絕對路徑給它:


資料庫會一直 apply archive log 直到找不到下一個檔案為止,例如上述以經 apply 到 #41 號的 archive log ,而此時 #42 序號的交易可能還在線上的 Redo Log 裡面還沒 switch 出來,如果線上的 Redo Log 沒有遺失的話,此時可以提供線上的 Redo Log 讓它 recover ,這樣的話就可以達到完整的資料庫還原,資料是完全沒有遺失的;如果線上的 Redo Log 已經遺失不存在了,那麼我們就只能 apply 到 #41 這個序號,這樣就會損失一個 Redo Log 的交易資料,雖然如此,但熱備份的還原已經是可以還原到最接近現在的時間點了。


recover 完成後,使用 alter database open resetlogs 將資料庫開啟,完成資料庫還原的程序:


由於有 archive log 的存在,因此熱備份是可以只單獨還原某一個檔案的,同樣需經過 recover 的程序,例如單獨將 users01.dbf 這個檔案進行還原:

SQL> alter database datafile '/u01/oradata/users01.dbf' offline;

SQL> !cp /u01/orabak/users01.dbf /u01/oradata/

SQL> recover datafile '/u01/oradata/users01.dbf';

SQL> alter database datafile '/u01/oradata/users01.dbf' online;


實務上來說,資料庫系統必須 7x24 不停地提供服務,不太會為了備份而將資料庫 shutdown ,因此冷備份很少使用,幾乎都是以熱備份為主要的方式。



2021年9月16日 星期四

10.4 Data Pump

Oracle Data Pump 為 Oracle 10g 開始推出的新功能, Data Pump 可以說是加強版的 Export 、 Import ,由 expdp 與 impdp 命令取代了原本的 exp 與 imp ,與傳統的 exp 、 imp 不同的是, exp 與 imp 是使用外部指令連接到資料庫進行匯出與匯入的動作,而 expdp 與 impdp 則是把外部指令轉換為資料庫內部的命令,使用的是 dbms_datapump 來進行匯出與匯入的動作,也就是說 expdp 與 impdp 是在資料庫內部運行的,當執行了 expdp 或 impdp ,會在資料庫產生一個 Data Pump Job ,經由這個 Job 來呼叫 dbms_datapump 從而完成匯出與匯入的動作,由於 Data Pump 是在資料庫內部運行的,並不會因為執行 expdp 、 impdp 的視窗被關閉後就會中斷,而 exp 與 imp 則是運行視窗被關閉後就會被中斷;另一個不同是,由於 Data Pump 是在資料庫內部運行,所以匯出的 Dump 檔案必須存放在資料庫主機上,而傳統的 exp 則是可以透過 tnsnames 將 Dump 檔匯出到 Client 主機上。


由於 Data Pump 所匯出的 Dump 檔案必須存放在資料庫主機上,所以在執行 Data Pump 之前必須於資料庫建立一個 Directory , Directory 的用意是在資料庫建立一個名稱,這個名稱是要對應作業系統上的一個位置,之後資料庫就會知道要將 Dump 檔匯出到作業系統上的那一個位置, Directory 必須使用 sys 使用者建立,而 sys 也是 Directory 的擁有者,如果其他使用者也要使用的話,必須授權給它,例如於資料庫建立兩個 Directory , expdir 與 impdir ,然後授權給 scott 與 hr 這兩個使用者:


SQL> create directory expdir as '/orabak';

SQL> create directory impdir as '/orabak2';

SQL> grant read,write on directory expdir to hr;

SQL> grant read,write on directory expdir to scott;

SQL> grant read,write on directory impdir to hr;

SQL> grant read,write on directory impdir to scott;


如果不使用某個 Directory ,可以使用 drop directory 命令來刪除。

透過 dba_directories 可以查詢目前資料庫所建立的 Directory 與所對應的路徑:


Data Pump Export 使用的是 expdp 命令,執行 expdp help=y 會列出所有可以使用的參數,一般來說只要簡單的指定帳號密碼 、 Dump 檔案存放路徑 (Directory) 、 Dump 檔案的名稱以及所要匯出的資料範圍 (Full 、 Schemas 、 Tables) 就可以進行匯出的動作:


$ export ORACLE_SID=ORA11

$ expdp \'/ as sysdba\' full=y directory=expdir dumpfile=full.dmp logfile=full.log job_name=expfull

  (匯出全資料庫)

$ expdp \'/ as sysdba\' schemas=hr directory=expdir dumpfile=hr.dmp logfile=exphr.log

  (匯出 hr 使用者所有物件)

$ expdp hr/welcome1 tables=employees,departments directory=expdir dumpfile=exp.dmp logfile=exp.log

  (匯出 employees 與 departments 兩個 Table)


Data Pump 會於資料庫內部建立一個 Job 來處理,透過 dba_datapump_jobs 可以查詢目前所進行的作業:


在執行 expdp 的時候可以帶入參數 job_name 自行為這個 job 命名,如果沒有使用 job_name 的話,系統會自行為這個 job 進行命名。


由於 Data Pump 是在資料庫裡面建立 Job 來執行,所以當 expdp 的執行介面被關閉時, Data Pump 的作業並不會因此停止,重新登入後可以使用 attach=<job_name> 來重新回到 Data Pump 執行的狀態,例如重回 expfull 這個 Job 的執行狀態:

$ export ORACLE_SID=ORA11

$ expdp \'/ as sysdba\' attach=expfull


在 attach 回去之後會進入到 Export> 介面,在此介面下可以對此 Job 進行狀態查詢 (status) 、 暫時停止 Job (stop_job) 、 重新開始 Job (start_job) 、 終止 Job (kill_job) 等動作:


expdp 一些比較常用的選項例如在 dumpfile 可以使用 %U ,這個選項可以自動切分並命名多個 Dump 檔案,例如 dumpfile=exp%U.dmp 就會自動產生 exp01.dmp 、 exp02.dmp 、exp03.dmp 等編號的 Dump 檔; parallel 可以設定多個 threads 來進行 Export 的動作; content 可以設定只匯出結構 (content=metadata_only) 或者是只匯出資料 (content=data_only) ; exclude 與 include ,可以指定只匯出或者是排除某些物件,例如只匯出 Procedure (include=procedure) 、不匯出 Index (exclude=index) ; parfile 用來指定參數檔, expdp 可以將所有要使用的參數設定為一個參數檔,然後用 parfile 來指定它就可以。


expdp 同樣也可以使用 query 條件式來匯出某些部分的資料,例如只匯出 employee_id < 200 的資料:

$ export ORACLE_SID=ORA11

$ expdp \'/ as sysdba\' tables=hr.employees directory=expdir query=\"where employee_id \<200\" dumpfile=emp.dmp logfile=emp.log


Data Pump Import 使用的是 impdp 命令,執行 impdp help=y 會顯示出所有可以使用的參數,同樣的只要簡單輸入帳號密碼, Dump 檔案名稱與位置就可以進行匯入的動作了。 impdp 與傳統的 imp 最大的不同是,傳統的 imp 要匯入 Table 的時候,必須先把相對應的使用者先建立好才可以進行匯入的動作,而 impdp 如果來源的 Dump 檔案是以 schema 層級匯出的話,如果使用者不存在,那麼 impdp 就會在匯入 Table 前自動建立使用者。 impdp 較常使用的參數除了上述 expdp 所提過的 parallel 、 exclude 、 include 、 job_name 、 parfile 之外,當匯入的 Table 已經存在的時候必須使用 table_exists_action 來告訴 impdp 必須進行何種動作, table_exists_action 可以為 append (接續著目前存在的資料進行匯入) 、 truncate (將 Table 的所有資料清空後重新匯入) 、 replace (將 Table 重新建立後再進行資料的匯入) 、 skip (跳過此 Table) ; remap_schema 用來將物件匯入到不同於來源的使用者; network_link 透過 db link 直接匯入資料,使用這個選項可以在不產生 Dump 檔案的情況下直接從來源資料庫將資料匯入。例如:


$ export ORACLE_SID=ORA11

$ impdp \'/ as sysdba\' directory=impdir dumpfile=emp%U.dmp logfile=imp.log

  (匯入 emp&U.dmp 所有 dump 檔案的內容)

$ impdp \'/ as sysdba\' directory=impdir dumpfile=hr.dmp remap_schema=hr:scott logfile=imphr.log

  (將原本由 hr 使用者匯出的 hr.dmp 匯入到 scott 這個使用者底下)

$ impdp hr/welcome1 directory=impdir dumpfile=emp.dmp table_exists_action=truncate logfile=impemp.log

  (匯入 emp.dmp 所有內容,如果 Table 已經存在,則將資料全部清空再匯入)

$ impdp \'/ as sysdba\' network_link=orcl schemas=scott logfile=imp_scott.log

  (透過 db link 的方式匯入 scott 使用者所有物件)


使用 Data Pump 必須要注意的是,如果要終止掉正在執行的 Export 、 Import 作業,傳統的 exp 與 imp 只需要從作業系統執行 kill -9 指令就可以終止,但是 expdp 與 impdp 是在資料庫內部產生 Job 來執行,光是 kill 掉 expdp 、 impdp 是無法終止 Data Pump 的,這麼做反而會讓 Data Pump Job 殘留在資料庫裡面,正確的作法必須要使用 attach=<job_name> 進入到 Export> 或是 Import> 介面,然後執行 kill_job ,這樣才是完整的終止 Data Pump 作業。


Data Pump 不像傳統的 exp 、 imp 必須再特別設定環境變數 NLS_LANG ,因為 Data Pump 是在資料庫內部運行,所以不會有字元集不匹配的問題。由上述範例可以看到, Data Pump 可以使用的選項非常多,使用起來比起傳統的 exp 、 imp 更有彈性也更為便利,雖然現今版本的資料庫還保有 exp 與 imp 的命令,但是已經漸漸地很少使用它了,而是使用 expdp 與 impdp 進行取代。



2021年9月14日 星期二

10.3 Export 與 Import

Export 與 Import 是用來將 Oracle 資料庫物件匯出與匯入的一種工具,主要的用途是作為資料庫的備份,或者是用來做資料庫的移轉與升級,例如要將一套 Oracle 10g 的資料庫升級為 Oracle 11g ,那麼就可以在一台新的機器上安裝好 Oracle 11g ,然後將 Oracle 10g 的資料庫 Export 再 Import 到 11g ,這樣就完成升級的動作。


使用 Export 這項工具,只要安裝完 Oracle 軟體,執行命令 exp 就可以使用,執行 exp help=y 會顯示出所有 exp 可使用的參數:


exp 可以匯出的範圍包括整個資料庫 (Full) ,或者是針對某些使用者的所有物件進行匯出 (Owner) ,也可以只匯出 Table ;使用上只要 exp 後面加上登入資料庫的帳號密碼,再加上要匯出的標的與匯出的檔名,這樣就可以簡單完成 export 的動作,例如:


$ export NLS_LANG=AMERICAN_AMERICA.AL32UTF8

$ export ORACLE_SID=ORA11

$ exp system/manager full=y file=/orabak/exp_full.dmp log=/orabak/exp_full.log

  (匯出資料庫所有物件)

$ exp system/manager owner=scott file=/orabak/exp_scott.dmp log=/orabak/exp_scott.log

  (匯出 scott 這個使用者的所有物件)

$ exp \'/ as sysdba\' tables=hr.regions,hr.emp file=/orabak/hr.dmp log=/orabak/exp_hr.log

  (使用 sys 登入資料庫來匯出 hr.regions 與 hr.emp 這兩個 Table)


除此之外, exp 還有一些比較常用的參數,例如 filesize ,用來限制一個 dmp 檔案的大小,早期受限於作業系統的限制,有檔案大小上限的問題,而要匯出的資料量又很大的時候,就必須使用 filesize 來限制與切分所匯出的 dmp 檔案,這邊要注意的是,使用 filesize 時,必須要列出所有 dmp 檔的檔名,否則 exp 作業會因為一個 dmp 檔達到 filesize 上限之後,不知道要使用什麼檔名來匯出下一個而停滯在那邊,例如限制 filesize 為 100MB ,那麼總共要匯出的資料有 300MB 的話,就必須指定三個 dmp 檔給它;使用 direct=y 參數可以直接從 Disk I/O 在 exp 過程當中不經過 cache ,可以加快 exp 的速度;如果只是要匯出 Table 的結構不匯出資料,那麼可以使用 rows=n 。例如使用 filesize 匯出 employees 這個 Table 的資料,以及匯出 department 這個 Table 的結構:

$ export NLS_LANG=AMERICAN_AMERICA.AL32UTF8

$ export ORACLE_SID=ORA11

$ exp scott/tiger tables=employees file=emp1.dmp,emp2.dmp,emp3.dmp filesize=100M direct=y log=emp.log

$ exp hr/welcome1 tables=department rows=n file=dep.dmp log=dep.log


exp 也可以透過 Query 參數來下條件,只匯出 Table 某些部分的資料,例如要匯出 employee_id < 200 的資料,那麼就可以在 exp 的過程中使用 Query 條件式來過濾:

$ export NLS_LANG=AMERICAN_AMERICA.AL32UTF8

$ export ORACLE_SID=ORA11

$ exp hr/welcome1 tables=emp file=exp_emp.dmp query=\"where employee_id\<200\" log=exp_emp.log


exp 還有一個特點,就是可以透過 tnsnames 來連接資料庫, exp 作業不一定要在 DB Server 上執行,透過 tnsnames 的連接可以將 dmp 檔匯出到 client 端的 Server 上,例如透過一台 PC 主機將 orcl 資料庫的資料匯出:

D:\> set NLS_LANG=AMERICAN_AMERICA.AL32UTF8

D:\> exp scott/tiger@orcl tables=emp file=D:\orabak\exp_emp.dmp log=D:\orabak\exp_emp.log


最後要注意的是,執行 exp 之前,都必須要設定環境變數 NLS_LANG 與資料庫的字元集相同,否則有可能因字元集的問題導致匯出的資料不正確。


同樣的 Import 這項工具,執行命令為 imp ,使用 imp help=y 會列出所有可套用的參數:


使用 imp 只需給予 dmp 檔就可以將物件匯入資料庫,其中必須指定一種選項,匯入 dmp 所有的內容 (full=y) ,或者是指定匯入的 schema (fromuser, touser) ,例如:

$ export NLS_LANG=AMERICAN_AMERICA.AL32UTF8

$ export ORACLE_SID=ORA11

$ imp \'/ as sysdba\' full=y file=emp1.dmp,emp2.dmp,emp3.dmp log=imp_emp.log

  (匯入所有 dmp 檔的內容)

$ imp system/manager fromuser=hr touser=hr file=exp_hr.dmp log=imp_hr.log

  (將 dmp 檔的內容,原本是從 hr 使用者匯出,現在也是匯入 hr 這個使用者底下)

$ imp system/manager fromuser=scott touser=hr file=exp_emp.dmp log=imp_hr.log

  (將 dmp 檔的內容,原本是從 scott 使用者匯出,現在匯入到 hr 這個使用者底下)


其餘較常使用的參數如 rows=n 不匯入資料; indexes=n 不匯入 index ; ignore=y 忽略 imp 過程中所有錯誤持續 import ,例如 import 過程中碰到資料重複的錯誤 Ora-0001 unique constraint violated ,要忽略掉這些重複的資料,其餘不重複的資料要繼續 import ,那麼就可以使用 ignore=y ,否則 imp 作業會因為發生錯誤而中斷開來; show=y 這個參數也蠻常使用,意思是由 dmp 檔案中產生出建立物件的 DDL ,不會真正的執行 import 的動作,例如從 exp_emp.dmp 中產生出 DDL 指令:


$ imp hr/hr file=exp_emp.dmp show=y log=imp_emp.log


同樣的在執行 imp 之前,也必須要設定環境變數 NLS_LANG 與資料庫字元集相同,否則也會因為字元集的不同導致匯入的資料發生錯誤。


由於 exp 、 imp 是將資料庫的物件匯出成一個 dmp 檔再匯入,所以這中間不會受到作業系統平台,或者是資料庫版本的限制,例如可以將一個在 AIX 平台上、 Oracle 9i 的 Table exp 出來,然後再將其 imp 到 Linux 平台、 Oracle 11g 的資料庫。在跨版本進行 exp 、 imp 時,需要注意的是,使用 exp 必須為比較低版本的,而 imp 可以是同版本或是更高版本的,例如由 Oracle 9i 移轉到 Oracle 10g ,那麼就可以使用 Oracle 9i 的 exp 將資料匯出,再使用 Oracle 10g 的 imp 將資料匯入;但是如果反過來,要將 Oracle 10g 的資料移轉到 Oracle 9i ,那麼就必須使用 Oracle 9i 的 exp ,透過 tnsnames 的方式連線到 Oracle 10g 進行 exp 的動作,然後才可以使用 Oracle 9i 的 imp 將資料匯入,因為高版本 exp 所產生出來的 dmp 檔是無法匯入到低版本的,所以這時候必須用低版本的 exp 來做匯出才行。


exp 、 imp 算是 Oracle 非常早期的工具,目前進行資料庫匯出匯入的動作大多都使用 Datapump ,已經很少使用 exp 、 imp 了。