CREATE TABLE AS SELECT,使用Oracle9i的External Table
Oracle 9i 的一項新特性就是 External Table,它就象一般的數據庫表同樣,擁有字段和數據類型約束,而且能夠查詢,可是表中的數據卻不存儲在數據庫中,而是在與數據庫相關聯的普通外部文件 裏。當你查詢 External Table 時,Oracle 將解析該文件並返回符合條件的數據,就象該數據存儲在數據庫表中同樣。
須要注意的是,你能夠在查詢語句中將 External Table 與數據庫中其餘表進行鏈接(Join),可是不能給 External Table 加上索引,而且不能插入/更新/刪除數據,畢竟它不是真正的數據庫表。另外,若是與數據庫相關聯的外部文件被改變或者被刪除,這會影響到 External Table 返回查詢結果,因此在變更前要先跟數據庫打招呼。
這種方法爲導入數據打開了新的一扇門。你能夠很 容易的將外部文件與數據庫相關聯,而且在數據庫中建立對應的 External Table,而後就能夠當即查詢數據,就象外部數據已經導入到數據庫表中同樣。惟一的不足須要明確,數據並未真正導入到數據庫中,當外部文件被刪除或覆蓋 時,數據庫將不能訪問 External Table 裏的數據,並且索引沒有被建立,訪問數據速度將有所緩慢。建立 CALLS_EXTERNAL(External Table表)以下,使之與外部數據文件關聯:
CREATE TABLE calls_external (call_id NUMBER, call_date DATE, emp_id NUMBER, call_type VARCHAR2(12), details VARCHAR2(25)) ORGANIZATION EXTERNAL ( TYPE oracle_loader DEFAULT DIRECTORY extract_files_dir ACCESS PARAMETERS ( RECORDS DELIMITED BY NEWLINE FIELDS TERMINATED BY ’,’ MISSING FIELD VALUES ARE NULL ( call_id, call_date CHAR DATE_FORMAT DATE MASK "yyyy-mm-dd:hh24:mi:ss", emp_id, call_type, details ) ) LOCATION (’calls.dat’) ); |
而後將 External Table 與真正被使用的表 CALLS 關聯同步,刪除 CALLS 表並重建它:
CREATE TABLE calls ( call_id NUMBER NOT NULL, call_date DATE NOT NULL, emp_id NUMBER NOT NULL, call_type VARCHAR2(12) NOT NULL, details VARCHAR2(25) ) TABLESPACE tbs1 NOLOGGING AS SELECT call_id, call_date, emp_id, call_type, details FROM calls_external; |
由於 CALLS 表是真正的數據庫表,能夠建立索引來加快訪問,表中的數據將被保留,即便外部數據文件被更新或被刪除。在建表語句中NOLOGGING關鍵字用於加快索引重建。
運用這種方法導入數據,總的導入時間爲 15 秒,進程佔用 CPU 的時間爲8秒,這比前一種方法稍微慢些,但不能就此認爲使用 External Table 導入數據必定比 OCI 批量插入慢。
這種方法的優勢是,未經進行大量的編寫代碼就取得了不錯的結果,不象 OCI 批量插入存在編碼錯誤風險,它還可使用 dbms_job 包調度數據導入進程,實現數據導入的自動化。其缺點是目標表必須先刪除後重建,若是隻須要導入增量數據時此方法就不合適了,另外用戶在表的重建過程當中訪問 數據時會遇到 "table or view does not exist" 的錯誤,它僅適用於 Oracle 9i 以上版本的數據庫。
INSERT Append as SELECT,使用 Oracle9i 的 External Table
上一種方法演示瞭如何建立與外部數據文件關聯的數據庫表,其表的數據是由外部數據文件映射過來。缺點是數據庫表須要被先刪除再重建來保持與外部數據文件 的一致和同步,對導入增量的數據而不須要刪除已有數據的狀況不合適。針對這種需求,Oracle 提供了 INSERT 語句外帶 APPEND 提示來知足。
INSERT /*+ APPEND */ INTO calls (call_id, call_date, emp_id, call_type, details) SELECT call_id, call_date, emp_id, call_type, details FROM calls_external; |
該語句讀取引用外部數據文件的 CALLS_EXTERNAL 表中內容,並將之增長到表 CALLS 中。Append 提示告訴 Oracle 使用快速機制來插入數據,同時能夠配合使用表的 NOLOGGING 關鍵字。
能夠預見這種方法與前一方法消耗了相同的時間,畢竟它們是使用 External Table 特性導入數據的不一樣階段解決方法。若是目標表不是空的,那將會消耗稍微長的時間(由於要重建更長的索引),而前一 CREATE TABLE as SELECT 方法是總體建立索引。
SQL*Loader的強大功能
SQL*Loader 是 Oracle 提供的導入實用程序,特別針對從外部文件導入大批量數據進入數據庫表。該工具已經有多年的歷史,每一次版本升級都使其更增強大、靈活和快捷,但遺憾的是它的語法倒是神祕而不直觀,而且只能從命令行窗口處進行調用。
儘管它有不直觀的缺點,但倒是最快最有效的導入數據方法。缺省狀況下它使用 "conventional path" 常規選項來批量導入數據,其性能提升度並不明顯。我建議使用更快速的導入參數選項,在命令行添加"direct=true" 選項調用 "direct path" 導入選項。在 "direct path" 導入實現中,程序在數據庫表的新數據塊的 high water mark 處直接寫入導入數據,縮短了數據插入的處理時間,同時優化使用了很是有效的B+二叉樹方法來更新表的索引。
運用這種方法,若是使 用缺省的 conventional path 導入選項,總的導入時間是 81 秒,進程佔用 CPU 時間大約是 12 秒,這包括了更新表的索引時間。若是使用 direct path 導入選項,總的導入時間竟是 9 秒,進程佔用 CPU 時間也僅僅是 3 秒,也包括了更新表的索引時間。
因而可知,儘管表中的索引在數據導入以前並無被刪除,使用SQL*Loader的direct path 導入選項仍然是快速和有效的。固然它也有缺點,就像NOLOGGING關鍵字同樣該方法不生成REDO日誌數據,導入進程出錯後將沒法恢復到先前狀態;在 數據導入過程當中表的索引是不起做用的,用戶此時訪問該表時將出現遲緩,固然在數據導入的過程當中最好不要讓用戶訪問表。
分區交換 (Partition Exchange)
以上討論的數據導入方法都有一個限制,就是要求用戶在導入數據完成以後才能夠訪問數據庫表。面對7×24不間斷訪問數據庫來講,若是咱們只是導入須要增 加的數據時,這種限制將對用戶的實時訪問產生影響。Oracle在這方面提供了表分區功能,它能夠減小導入數據操做對用戶實時訪問數據的影響,操做模式就 象使用可熱插拔的硬盤同樣,只不過這裏的硬盤換成了分區(Partition)而已。須要聲明的是 Partitioning 分區功能只有在企業版數據庫中才提供。
在一個被分區過的表中,呈現給用戶的表是多個分區段(segments)的集合。分區能夠在需 要時被添加,在維護時被卸載或刪除,分區表能夠和數據庫中的表交換數據,只要它們的表結構和字段類型是一致的,交換後的分區表將擁有與之互動的表的數據。 須要注意的是,這種交換隻是在Oracle數據庫的數據字典層面上進行,並無數據被實際移動,因此分區表交換是極其快速的。
爲了建立實驗環境,先假設CALLS表是個分區表,要建立一個空的分區PART_01012004,用來保存2004年1月1日的呼叫數據。而後須要再建立一臨時表爲CALLS_TEMP,該表與CALLS表擁有相同的字段和數據類型。
咱們使用先前介紹的導入方法將十萬條數據導入到CALLS_TEMP表中,能夠耐心等待數據徹底導入到CALLS_TEMP表中,而且建立好索引和相關 約束條件,全部這一切操做並不影響用戶實時訪問CALLS表,由於咱們只對CALLS_TEMP臨時表進行了操做。一旦數據導入完成, CALLS_TEMP表就存有2004年1月1日的呼叫數據。同時利用CALLS表中名爲PART_01012004的空分區,使用以下語句執行分區交 換:
ALTER TABLE calls EXCHANGE PARTITION part_01012004 WITH TABLE calls_temp INCLUDING INDEXES WITHOUT VALIDATION; |
分區交換操做將很是快速地只更新CALLS表的數據字典,PART_01012004分區表即刻擁有CALLS_TEMP表的全部數據,而 CALLS_TEMP表變爲空表。假定CALLS表使用局部索引而非全局索引,上述語句中的INCLUDING INDEXES將保證分區交換包括索引的可用性,WITHOUT VALIDATION 指明不檢查交替表中數據的匹配,加快了交換的速度。
結論
以上探討了Oracle數據庫的多種數據導入方法,每種方法都有其優缺點和適用環境,可以知足你不一樣的導入需求,固然你須要在瞭解了這些方法後,在速度、簡易性、靈活性、可恢復性和數據可用性之間尋求最佳導入方案。
爲了對比各類方法的效果,咱們建立了一個實例來展現各類方法的導入效率和效果,從中你能夠選擇最適合的方法用於從此的數據導入工做。同時請記住,本文並未囊括全部的ORACLE數據導入技術(好比並行數據導入技術),這須要咱們繼續不懈的探索和嘗試。
數據導入方法 |
整體導入時間(秒) |
導入進程佔用CPU時間(秒) |
逐條數據插入INSERT |
172 |
52 |
逐條數據插入INSERT,表暫無索引 |
130 |
35 |
批量插入,表暫無索引 |
14 |
7 |
Create As Select,使用Oracle9i的External Table |
15 |
8 |
INSERT Append as SELECT,使用Oracle9i的External Table |
15 |
8 |
SQL*Loader conventional path 缺省導入選項 |
81 |
12 |
SQL*Loader direct path 導入選項 |
9 |
3 |