問題:當一個表的數據量超過一億條,要刪除其中的5000w條,如何處理。
如果直接使用delete語句,會涉及到到大量的磁盤IO,並產生大量的數據庫日志,效率很低,刪除速度慢,可能導致事務中斷,甚至有服務器硬盤空間撐爆的可能。
本文提供的思路是先將數據表需要保留的數據不帶索引導出,然后導入一個新表中 ,對新表重建索引后將老表、新表進行重命名,這樣就完成了刪除操作,效率有了很大提升。
主要分為三步,1.數據導出2. 數據導入 3.表以及索引重命名 。下面腳本是運行在oracle數據庫上。
具體步驟如下:
1.數據導出:
進入數據庫:sqlplus ,輸入用戶名與密碼。進入sql運行界面。
創建虛擬目錄:create or replace directory exp_dir as '/home/oracle/';
給目錄授權,若失敗繼續:grant read,write on directory exp_dir to oracle;
提交:commit;
退出數據庫:exit;
導出全量數據: expdp user/passwd@sername dumpfile=exp_table_eg_his_bak.dmp directory=exp_dir tables= exp_table_eg_his compression=all
dumpfile是指明dump文件名,directory是上面建立的虛擬目錄,tables指明要導出的表。compression說明要對數據進行壓縮,減少磁盤占用。數據量比較大,導出時間長,建議后台運行。
如果沒有數據庫用戶密碼,可使用操作系統oracle的權限以管理員身份進行導出。腳本如下:
expdp \'/ as sysdba \' dumpfile= exp_table_eg_his.bak .dmp directory=exp_dir tables= user.exp_table_eg_his compression=all
注意,exp_table_eg_his前要加user.,用以說明是哪個用戶的表。導出全量的數據只是為了備份而已。
導出保留數據 :
expdp user/passwd123@sername dumpfile=exp_table_eg_his_new.dmp directory=exp_dir tables= exp_table_eg_his Query=\"where plat_number like \'2018%\'\" exclude=index
這里需要注意,query查詢條件中的“”,‘’都要用\進行轉義,否則會報錯,exclude參數用來排除索引,oracle的索引是全局的,相同的索引名只能存在一個,為了后續方便導入,需要導出時把索引排除。
2. 數據導入:
impdp user/passwd123@sername directory=exp_dir dumpfile=exp_table_eg_his_new.dmp remap_table= exp_table_eg_his: exp_table_eg_his _new
remap_table用來將導入時將dump的表映射為新的表名。
進入數據庫:進入toad
重建索引:
create unique INDEX exp_table_eg_his_ix_new ON exp_table_eg_his_new (plat_number) 。
關於建索引,最好將原表的的索引創建腳本導出,修改下索引名字與表名,這樣可以保證索引的參數一致。
3. 重命名表與索引:
表重命名:alter table exp_table_eg_his rename to exp_table_eg_his _bak
alter table exp_table_eg_his _new rename to exp_table_eg_his
索引重命名:
alter index exp_table_eg_his_ix rename to exp_table_eg_his_ix_bak
alter index exp_table_eg_his_ix_new rename to exp_table_eg_his_ix
如果代碼中沒有顯式用到索引名字,在數據庫表重命名后索引也可以不用重命名。
刪除原his表:drop table exp_table_eg_his_bak。備份表已無用,可以刪掉了。