Oracle的pipelined函式實現高效能大資料處理
原文地址:http://mikixiyou.iteye.com/blog/1673672
在plsql開發中,會涉及到一些大資料量表的資料處理,如將某記錄數超億的表的記錄經過處理轉換插入到另外一張或幾張表。
常規的操作方法固然可以實現,但時間、磁碟IO、redo日誌等等都非常大。Oracle 提供了一種高階函式,可以將這種資料處理的效能提升到極限。這種函式稱為管道函式。
在實際專案中,管道函式會和表函式、資料流函式(即表函式和CURSOR結合)、資料集合、並行度一起使用,達到大資料處理的效能頂峰。
下面是一個例子,將表t_ss_normal的記錄插入到表t_target中,插入過程中有部分轉換操作。
我分成四個方法來實現這個資料處理操作。
第一個方法,也是最常規的方法,程式碼如下:
create table T_SS_NORMAL
(
owner VARCHAR2(30),
object_name VARCHAR2(128),
subobject_name VARCHAR2(30),
object_id NUMBER,
data_object_id NUMBER,
object_type VARCHAR2(19),
created DATE,
last_ddl_time DATE,
timestamp VARCHAR2(19),
status VARCHAR2(7),
temporary VARCHAR2(1),
generated VARCHAR2(1),
secondary VARCHAR2(1)
);
/
create table T_TARGET
(
owner VARCHAR2(30),
object_name VARCHAR2(128),
comm VARCHAR2(10)
);
這是源表和目標表的表結構。現在源表有200W條,其資料來自dba_objects檢視。
create or replace package pkg_test is
procedure load_target_normal;
end pkg_test;
create or replace package body pkg_test is
procedure load_target_normal is
begin
insert into t_target (owner, object_name, comm)
select owner, object_name, 'xxx' from t_ss_normal;
commit;
end;
begin
null;
end pkg_test;
一個insert into select語句搞定這個資料處理,簡單。
第二方法,採用管道函式實現這個資料處理。
create type obj_target as object(
owner VARCHAR2(30), object_name VARCHAR2(128), comm varchar2(10)
);
/
create or replace type typ_array_target as table of obj_target;
/
create or replace package pkg_test is
function pipe_target(p_source_data in sys_refcursor) return typ_array_target
pipelined;
procedure load_target;
end pkg_test;
首先建立兩個自定義的型別。obj_target的定義和t_target的表結構一致,用於儲存每一條目標表記錄。typ_array_target用於管道函式的返回值。
接著定義一個管道函式。
普通函式的結尾加一個pipelined關鍵字,就是管道函式。這個函式的返回引數型別為集合,這是為了使其能作為表函式使用。表函式就是在from子句中以table(v_resultset)呼叫的,v_resultset就是一個集合型別的引數。
最後定義一個呼叫儲存過程。
在包體中定義該管道函式和呼叫儲存過程。管道函式pipe_target的傳入引數一個sys_refcursor型別。這是一個遊標,可以理解為使用select * from table才能得到的結果集。
你也可以不用這個傳入的遊標,取而代之,在函式中定義一個遊標,也一樣使用。
function pipe_target(p_source_data in sys_refcursor) return typ_array_target
pipelined is
r_target_data obj_target := obj_target(null, null, null);
r_source_data t_ss%rowtype;
begin
loop
fetch p_source_data
into r_source_data;
exit when p_source_data%notfound;
r_target_data.owner := r_source_data.owner;
r_target_data.object_name := r_source_data.object_name;
r_target_data.comm := 'xxx';
pipe row(r_target_data);
end loop;
close p_source_data;
return;
end;
procedure load_target is
begin
insert into t_target
(owner, object_name, comm)
select owner, object_name, comm
from table(pipe_target(cursor(select * from t_ss_normal)));
commit;
end;
關鍵字 pipe row 的作用是將obj_target插入到typ_array_target型別的陣列中,管道函式自動返回這些資料。
因為源表的資料量會非常大,所以在fetch取值時會使用bulk collect ,實現批次取值。這樣做可以減少plsql引擎和sql引擎的控制轉換次數。這種轉換稱為上下文切換。
function pipe_target_array(p_source_data in sys_refcursor,
p_limit_size in pls_integer default c_default_limit)
return typ_array_target
pipelined is
r_target_data obj_target := obj_target(null, null, null);
type typ_source_data is table of t_ss%rowtype index by pls_integer;
aa_source_data typ_source_data;
begin
loop
fetch p_source_data bulk collect
into aa_source_data;
exit when aa_source_data.count = 0;
for i in 1 .. aa_source_data.count loop
r_target_data.owner := aa_source_data(i).owner;
r_target_data.object_name := aa_source_data(i).object_name;
r_target_data.comm := 'xxx';
pipe row(r_target_data);
end loop;
end loop;
close p_source_data;
return;
end;
procedure load_target_array is
begin
insert into t_target
(owner, object_name, comm)
select owner, object_name, comm
from table(pipe_target_array(cursor (select * from t_ss_normal),
100));
commit;
end;
還可以使用並行度,使得管道函式可以多程式同時執行。並行度還有一個好處,就是將資料插入方式從常規路徑轉換為直接路徑。直接路徑可以大量減少redo日誌的生成量。
function pipe_target_parallel(p_source_data in sys_refcursor,
p_limit_size in pls_integer default c_default_limit)
return typ_array_target
pipelined
parallel_enable(partition p_source_data by any) is
r_target_data obj_target := obj_target(null, null, null);
type typ_source_data is table of t_ss%rowtype index by pls_integer;
aa_source_data typ_source_data;
begin
loop
fetch p_source_data bulk collect
into aa_source_data;
exit when aa_source_data.count = 0;
for i in 1 .. aa_source_data.count loop
r_target_data.owner := aa_source_data(i).owner;
r_target_data.object_name := aa_source_data(i).object_name;
r_target_data.comm := 'xxx';
pipe row(r_target_data);
end loop;
end loop;
close p_source_data;
return;
end;
procedure load_target_parallel is
begin
execute immediate 'alter session enable parallel dml';
insert /*+parallel(t,4)*/
into t_target t
(owner, object_name, comm)
select owner, object_name, comm
from table(pipe_target_array(cursor (select /*+parallel(s,4)*/
*
from t_ss_normal s),
100));
commit;
end;
在測試過程中,我測試200W記錄的操作,時間從24秒降到到8秒,重做日誌也降低更多。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29812844/viewspace-1878507/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- java大資料處理:如何使用Java技術實現高效的大資料處理Java大資料
- oracle函式大全-字串處理函式Oracle函式字串
- Oracle函式-->字元處理Oracle函式字元
- Oracle中利用函式索引處理資料傾斜案例Oracle函式索引
- sql(oracle)資料處理實用總結開窗函式(over partition)使用SQLOracle函式
- [MYSQL -11]使用函式處理資料MySql函式
- Oracle 的管道化表函式(Pipelined Table) 轉Oracle函式
- MySQL-日期和資料處理函式MySql函式
- 使用自定義函式實現資料編解碼、格式處理與業務告警函式
- pipelined函式例項函式
- 分散式是大資料處理的萬用藥?分散式大資料
- plsql 除錯 pipelined 函式SQL除錯函式
- CnosDB:深入瞭解時序資料處理函式函式
- 11. 使用MySQL之使用資料處理函式MySql函式
- python字串處理函式大總結Python字串函式
- (特徵工程實戰)ML最實用的資料預處理與特徵工程常用函式!特徵工程函式
- 磁碟處理函式函式
- 字元處理函式字元函式
- 【雲端大資料實戰】大資料誤區、大資料處理步驟分析大資料
- Serverless 在大規模資料處理的實踐Server
- 大資料處理的基本流程大資料
- Flink處理函式實戰之四:視窗處理函式
- 管道函式及表函式的測試PIPELINED__PIPE ROW函式
- 剖析大資料平臺的資料處理大資料
- C#實現DataTable資料分割處理C#
- Flink處理函式實戰之五:CoProcessFunction(雙流處理)函式Function
- Oracle 中的 TO_DATE 和 TO_CHAR 函式 日期處理Oracle函式
- 計算機程式的思維邏輯 (93) – 函式式資料處理 (下)計算機函式
- 計算機程式的思維邏輯 (93) - 函式式資料處理 (下)計算機函式
- 計算機程式的思維邏輯 (92) - 函式式資料處理 (上)計算機函式
- 基於Spark的大資料實時處理開課Spark大資料
- 大資料常用處理框架大資料框架
- 陣列處理函式陣列函式
- SqlServer——字串處理函式SQLServer字串函式
- 安全字串處理函式字串函式
- 檔案處理函式函式
- 時間處理函式函式
- 處理中英文的函式函式