示例表結構和數據集
為了演示和比較各種數據導入方法,我假定數據導入任務是將外部文件數據導入到 Oracle 數據庫的CALLS表中,外部數據文件包含十萬條呼叫中心記錄,將近 6MB 的文件大小,具體的數據示例如下:
82302284384,2003-04-18:13:18:58,5001,投訴,手機三包維修質量
82302284385,2003-04-18:13:18:59,3352,咨詢,供水熱線的號碼
82302284386,2003-04-18:13:19:01,3142,建議,增設公交線路
接受導入數據的表名是 CALLS,表結構如下:
Name Null? Type Comment
------------ --------- ------------- -----------------
CALL_ID NOT NULL NUMBER Primary key
CALL_DATE NOT NULL DATE Non-unique index
EMP_ID NOT NULL NUMBER
CALL_TYPE NOT NULL VARCHAR2(12)
DETAILS VARCHAR2(25)
逐條數據插入INSERT
數據導入的最簡單方法就是編寫 INSERT 語句,將數據逐條插入數據庫。這種方法只適合導入少量數據,如 SQL*Plus 腳本創建某個表的種子數據。該方法的最大缺點就是導入速度緩慢,占用了大量的 CPU 處理時間,不適合大批量數據的導入;而其主要優點就是導入構思簡單又有修改完善的彈性,不需要多做其它的准備就可以使用。如果你有很多時間沒法打發,又想折磨一下數據庫和 CPU,那這種方法正適合你。
為了與其它方法做比較,現將十萬條記錄通過此方法導入到 CALLS 表中,總共消耗 172 秒,其中導入進程占用 CPU 時間為 52 秒。
逐條數據插入 INSERT,表暫無索引
為什麼上一種方法占用了較多的 CPU 處理時間,關鍵是 CALLS 表中已創建了索引,當一條數據插入到表中時,Oracle 需要判別新數據與老數據在索引方面是否有沖突,同時要更新表中的所有索引,重復更新索引會消耗一定的時間。因此提高導入速度的好辦法就是在創建表時先不創建索引或者在導入數據之前刪除所有索引,在外部文件數據逐條插入到表中後再統一創建表的索引。這樣導入速度會提高,同時創建的索引也很緊湊而有效,這一原則同樣適用於位圖索引(Bitmap Index)。對於主要的和唯一的關鍵約束(key constraints),可以使之先暫時失效(disabling)或者刪除約束來獲得同樣的效果,當然這些做法會對已經存在的表的外鍵約束產生相關的影響,在刪除前需要通盤斟酌。
需要說明的是,這種方法在表中已存在很多數據的情況下不太合適。例如表中已有九千萬條數據,而此時需要追加插入一千萬條數據,實際導入數據節省的時間將會被重新創建一億條數據的索引所消耗殆盡,這是我們不希望得到的結果。但是,如果要導入數據的表是空的或導入的數據量比已有的數據量要大得多,那麼導入數據節省的時間將會少量用於重新創建索引,這時該方法才可以考慮使用。 加快索引創建是另一個需要考慮的問題。為了減少索引創建中排序的工作時間,可以在當前會話中增加 SORT_AREA_SIZE 參數的大小,該參數允許當前會話在內存的索引創建過程中執行更多的排序操作。同樣還可以使用 NOLOGGING 關鍵字來減少因創建索引而生成的 REDO 日志量,NOLOGGING 關鍵字會對數據庫的恢復和 Standby 備用數據庫產生明顯的影響,所以在使用之前要仔細斟酌,到底是速度優先還是穩定優先。
運用這種方法,先刪除 CALLS 表的主鍵和不唯一的索引,然後逐條導入數據,完成後重新創建索引( 表在導入數據前是空的)。該方法總共消耗 130 秒,包括重建索引的時間,其中導入進程占用 CPU 時間為 35秒。
這種方法的優點是可以加快導入的速度並使索引更加緊湊有效;缺點是缺乏通用性,當你對表增加新的復雜的模式元素(索引、外鍵等)時你需要添加代碼、修改導入執行程序。另外針對 7*24 在線要求的數據庫在線導入操作時,刪除表的索引會對在線用戶的查詢有很大的性能影響,同時也要考慮,主要或唯一的關鍵約束條件的刪除或失效可能會影響到引用它們的外鍵的使用。
批量插入,表暫無索引
在Oracle V6 中 OCI 編程接口加入了數組接口特性。數組操作允許導入程序讀取外部文件數據並解析後,向數據庫提交SQL語句,批量插入 SQL 語句檢索出的數據。Oracle 僅需要執行一次 SQL 語句,然後在內存中批量解析提供的數據。批量導入操作比逐行插入重復操作更有效率,這是因為只需一次解析 SQL 語句,一些數據綁訂操作以及程序與數據庫之間來回的操作都顯著減少,而且數據庫對每一條數據的操作都是重復可知的,這給數據庫提供了優化執行的可能。其優點是數據導入的總體時間明顯減少,特別是進程占用 CPU 的時間。
需要提醒的是,通過 OCI 接口確實可以執行數據批量導入操作,但是許多工具和腳本語言卻不支持使用此功能。如果要使用該方法,需要研究你所使用的開發工具是否支持 OCI 批量操作功能。導入程序需要進行復雜的編碼並可能存在錯誤的風險,缺乏一定的彈性。
運用上述方法,程序將外部數據提取到內存中的數組裡,並執行批量插入操作(100行/次),保留了表的刪除/重建索引操作,總的導入時間下降到 14 秒,而進程占用 CPU 的時間下降到7秒,可見實際導入數據所花費的時間顯著下降了 95%。