寫有效的歷史資料遷移sql
對於高併發oltp系統,生產庫可能只需保留當前幾個月的資料,之前的資料要全部遷移到歷史庫中。那麼,如何處理這樣的需求,如何寫合適的歷史遷移程式呢?
1.常規寫法
begin
--遷移資料
insert into tb_users
select *
from tb_users_dbc a
where gmt_modified <= trunc(sysdate) - v_day and rownum<5000000;
--刪除原表資料
delete from tb_users_dbc
where gmt_modified <= trunc(sysdate) - v_day and rownum<5000000;
commit;
end;
--遷移資料
insert into tb_users
select *
from tb_users_dbc a
where gmt_modified <= trunc(sysdate) - v_day and rownum<5000000;
--刪除原表資料
delete from tb_users_dbc
where gmt_modified <= trunc(sysdate) - v_day and rownum<5000000;
commit;
end;
2.使用for迴圈
declare
v_counts number := 0;
begin
--中間表
insert into tmp_tb_users
select *
from tb_users_dbc
where gmt_modified <= trunc(sysdate) - v_day and rownum<5000000;
commit;
for i in (select id from tmp_tb_users) loop
--資料遷移
insert into tb_users
select * from tb_users_dbc where id = i.id;
delete from tb_users_dbc where id = i.id;
v_counts := v_counts + 1;
--分批提交
if mod(v_counts, 100) = 0 then
commit;
end if;
end loop;
end;
v_counts number := 0;
begin
--中間表
insert into tmp_tb_users
select *
from tb_users_dbc
where gmt_modified <= trunc(sysdate) - v_day and rownum<5000000;
commit;
for i in (select id from tmp_tb_users) loop
--資料遷移
insert into tb_users
select * from tb_users_dbc where id = i.id;
delete from tb_users_dbc where id = i.id;
v_counts := v_counts + 1;
--分批提交
if mod(v_counts, 100) = 0 then
commit;
end if;
end loop;
end;
3.使用bulk collect
declare
type rec_rids is table of varchar2(32);
v_rids rec_rids;
cursor cur_aids is
select id
from tb_users_dbc
where gmt_modified <= trunc(sysdate) - v_day and rownum<5000000;
begin
open cur_aids;
loop
fetch cur_aids BULK COLLECT INTO v_rids LIMIT 1000;
for i in 1 .. v_rids.count loop
--資料遷移
insert into tb_users
select * from tb_users_dbc where id = v_rids(i);
delete from tb_users_dbc where id = v_rids(i);
end loop;
commit;
EXIT WHEN v_rids.COUNT = 0;
end loop;
close cur_aids;
end;
type rec_rids is table of varchar2(32);
v_rids rec_rids;
cursor cur_aids is
select id
from tb_users_dbc
where gmt_modified <= trunc(sysdate) - v_day and rownum<5000000;
begin
open cur_aids;
loop
fetch cur_aids BULK COLLECT INTO v_rids LIMIT 1000;
for i in 1 .. v_rids.count loop
--資料遷移
insert into tb_users
select * from tb_users_dbc where id = v_rids(i);
delete from tb_users_dbc where id = v_rids(i);
end loop;
commit;
EXIT WHEN v_rids.COUNT = 0;
end loop;
close cur_aids;
end;
很少考慮常規寫法,資料遷移一般會選擇採用2,3種方法。
相比for遷移方式,採用bulk collect避免了上下文切換,在大批量資料遷移中還是有很大優勢的,推薦採用bulk collect資料遷移方案。
Asktom上有很多關於歷史遷移方案的帖子,Tom的答案一直都是常規寫法,也就是上面的第一種寫法,可是常規寫法消耗大量的資源,出現異常時整個事務都得回滾。因此很多人都認為Tom的方案不可行,認為Tom並沒有接觸過大資料庫等。
4.藉助Tom的思想,把遷移的資料拆分成n個小表,對n個小表進行遷移
declare
pagecount number;
sumcount number;
loopcount number;
begin
--取要遷移的資料
execute immediate 'truncate table tmp_tb_users';
insert into tmp_tb_users
select id
from tb_users_dbc
where gmt_modified <= trunc(sysdate) - v_day and rownum < 5000000;
--計算遷移總數
select count(*) into sumcount from tmp_tb_users;
--設定每次遷移條數
pagecount = 2000;
--得到迴圈次數
loopcount := sumcount / pagecount + 1;
for i in 1 .. loopcount loop
begcount := (i - 1) * pagecount + 1;
endcount := i * pagecount;
--構建中間小表
execute immediate 'truncate table mid_tb_users';
insert into mid_tb_users
select id, b.rn
from tmp_tb_users b where b.rn >= begcount and b.rn <= endcount;
--小表和原表進行關聯,遷移資料
insert into tb_users
select f.*
from mid_tb_users t, tb_users_dbc f
where t.biz_order_id = f.biz_order_id
and t.rn >= begcount and t.rn < = endcount;
--刪除原表資料
delete from tb_users_dbc where id in (select id from mid_tb_users);
commit;
end loop;
end;
pagecount number;
sumcount number;
loopcount number;
begin
--取要遷移的資料
execute immediate 'truncate table tmp_tb_users';
insert into tmp_tb_users
select id
from tb_users_dbc
where gmt_modified <= trunc(sysdate) - v_day and rownum < 5000000;
--計算遷移總數
select count(*) into sumcount from tmp_tb_users;
--設定每次遷移條數
pagecount = 2000;
--得到迴圈次數
loopcount := sumcount / pagecount + 1;
for i in 1 .. loopcount loop
begcount := (i - 1) * pagecount + 1;
endcount := i * pagecount;
--構建中間小表
execute immediate 'truncate table mid_tb_users';
insert into mid_tb_users
select id, b.rn
from tmp_tb_users b where b.rn >= begcount and b.rn <= endcount;
--小表和原表進行關聯,遷移資料
insert into tb_users
select f.*
from mid_tb_users t, tb_users_dbc f
where t.biz_order_id = f.biz_order_id
and t.rn >= begcount and t.rn < = endcount;
--刪除原表資料
delete from tb_users_dbc where id in (select id from mid_tb_users);
commit;
end loop;
end;
1.優於常規寫法,可以分批多次進行提交,加入異常處理可以避免全部資料回滾。
2.優於for遷移,藉助中間小表一次遷移多條記錄,大大降低了insert,delete的執行次數。
3.主要是提供給大家一種思路。
結論:
其實寫法好沒有好壞之分,關鍵在於怎麼用,就大批量遷移資料來說,我覺得3,4都是比較可行的方案。歡迎大家拍磚討論,也歡迎貢獻更好的資料遷移辦法。
注:上面指令碼是虛擬碼
<!----EOF--
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10742223/viewspace-235564/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 使用SQL SERVER儲存過程實現歷史資料遷移SQLServer儲存過程
- 儲存所有歷史提交資料下遷移git倉庫Git
- 異構資料庫遷移 sql等價改寫資料庫SQL
- SQL Server資料庫遷移SQLServer資料庫
- Oracle 9i 11g歷史庫升級遷移資料至19c CDBOracle
- 走進資料的歷史
- SQL Server 資料庫最小當機遷移方案GESQLServer資料庫
- 伺服器資料遷移的方法-硬體不同如何遷移資料伺服器
- Kafka資料遷移Kafka
- Harbor資料遷移
- gitlab資料遷移Gitlab
- 資料庫遷移資料庫
- 從 SQL Server 到 MySQL (一):異構資料庫遷移ServerMySql資料庫
- 案例分析:700G SQL Server資料庫遷移HGSQLServer資料庫
- 歷史股票資料的爬取
- 資料遷移(1)——通過資料泵表結構批量遷移
- ABP8.1的資料遷移
- Mysql資料遷移方法MySql
- 【Hive】hive資料遷移Hive
- 【Redis】 redis資料遷移Redis
- redis資料庫遷移Redis資料庫
- congregate遷移gitlab資料Gitlab
- 系統資料遷移
- 資料庫遷移 :理解資料庫
- laravel資料庫遷移Laravel資料庫
- Fastdfs資料遷移方案AST
- 金倉資料庫資料遷移實戰:從MySQL到KES的順利遷移資料庫MySql
- Laravel 使用 sql 語句 和 sql 檔案 來建立執行資料庫遷移LaravelSQL資料庫
- SQL Server 查詢歷史執行的SQL語句SQLServer
- Oracle檢視歷史TOP SQLOracleSQL
- Laravel migration (資料庫遷移) 的使用Laravel資料庫
- 關於禪道的資料遷移
- linux mysql資料庫遷移LinuxMySql資料庫
- django資料庫遷移-15Django資料庫
- geoserver資料儲存遷移Server
- 用rman遷移資料庫資料庫
- 資料庫遷移手記資料庫
- 遷移MySQL 5.7資料庫MySql資料庫
- 資料庫遷移神器——Flyway資料庫