产品表:
PID START_DATE END_DATE PRODUCT_SET_ID CREATED_DATE UPDATED_DATE PRODUCT_NAME COMPANY_NM PRICE
1 04/01/11 06/30/11 12 09/06/16 09/06/16 Apple ABC 50
2 04/01/10 06/30/10 12 09/06/16 09/06/16 Toothpaste PQR 80
3 07/01/11 09/30/11 12 09/06/16 09/06/16 Soap DOVE 53
4 04/01/12 06/30/12 12 09/06/16 09/06/16 TV ONIDA 50000
订单表:
OID PID PRODUCT_ID SEQ_ID TYPE_ID CREATED_DATE UPDATED_DATE NUMBER_VALUE TEXT_VALUE
11 1 1 1 1 09/06/16 09/06/16 5
12 1 2 1 6 09/06/16 09/06/16 50
13 2 1 1 3 09/06/16 09/06/16 3
14 2 2 1 7 09/06/16 09/06/16 80
VA表:
Product_ID Product_Name
1 Apple
2 Orange
3 Toothpaste
4 Soap
5 TV
6 ABC
7 PQR
8 DOVE
9 ONIDA
VA_IN_TB
TB_NM COL_NM PRODUCT_ID SEQ_ID
Product_TB Apple 1 1
Product_TB Orange 2 1
Product_TB Toothpaste 3 1
Product_TB Soap 4 1
Product_TB TV 5 1
Product_TB ABC 6 1
Product_TB PQR 7 1
Product_TB DOVE 8 1
Product_TB ONIDA 9 1
我还在产品表中添加了索引:
CREATE INDEX INDX_PID ON PRODUCT_TABLE(PID);
生成订单表的存储过程:
REC_COUNT:= SELECT COUNT(*) FROM PRODUCT_TABLE;
Loop_CT :=( REC_COUNT/2000000) +1;
SELECT MIN(PID) INTO LOWER_LIMIT FROM PRODUCT_TABLE;
UPPER_LIMIT := LOWER_LIMIT +2000000;
FOR i in 1..LOOP_COUNT LOOP
Create Table Temp_1 Nologging as
SELECT ORDER_SEQ.NEXTVAL OID,
A.PID,A.PRODUCT_ID,
A.SEQ_ID,
A.VALUE,
B.TYPE_ID
FROM
(
SELECT A.PID,
A.VA_ID,
A.SEQ_ID,
A.VALUE,
B.TYPE_NAME
FROM
(
select A.PID,
B.PRODUCT_ID,
B.SEQ_ID,
PRODUCT_NAME VALUE
from PRODUCT_TABLE A
JOIN VA_IN_TB B
ON REPLACE(A.PRODUCT_NAME,'''','')=REPLACE(B.COL_NM,'''','')
AND A.PID BETWEEN LOWER_LIMIT AND UPPER_LIMIT
union all
select A.PID,
B.PRODUCT_ID,
B.SEQ_ID,
PRICE VALUE
from PRODUCT_TABLE A
JOIN VA_IN_TB B
ON REPLACE(A.COMPANY_N,'''','')=REPLACE(B.COL_NM,'''','')
AND A.PID BETWEEN LOWER_LIMIT AND UPPER_LIMIT
) A
LEFT JOIN VA_TB B
ON A.PRODUCT_ID=B.PRODUCT_ID
) A
LEFT JOIN VA_TB B
ON A.TYPE_NAME=B.PRODUCT_NAME
Insert INTO ORDER_TB
SELECT * FROM TEMP_1;
Commit;
DROP TABLE TEMP_1;
LOWER_LIMIT := UPPER_LIMIT + 1;
UPPER_LIMIT := UPPER_LIMIT + 2000000;
End LOOP;
我们在产品表中有2000万条记录,我需要使用上述存储过程基于产品表生成订单表。我尽可能地尝试优化,但在Oracle Standard One上执行仍需要8个多小时。我该如何优化此代码?
答案 0 :(得分:0)
请参阅下文,了解如何使用集合来实现目标。我在开始时询问你的代码是否正常工作因为我看到很多错误,无论如何它都不会运行。我没有测试代码,因为我可以看到你只发布了一部分代码,而且很多东西都不太清楚。我的代码只是提供一个你可以实现的代码片段。
Declare
REC_COUNT number;
Loop_CT number;
LOWER_LIMIT number;
UPPER_LIMIT number;
Cursor cur_rec (LWR_LMT number,UPR_LMT number) is
/******Assuming all your joins are working fine ..However it doesnot look so from the code your posted. ***/
SELECT ORDER_SEQ.NEXTVAL OID,
A.PID,
A.PRODUCT_ID,
A.SEQ_ID,
A.VALUE,
B.TYPE_ID
FROM
(
SELECT A.PID,
A.VA_ID,
A.SEQ_ID,
A.VALUE,
B.TYPE_NAME
FROM
(
select A.PID,
B.PRODUCT_ID,
B.SEQ_ID,
PRODUCT_NAME VALUE
from PRODUCT_TABLE A
JOIN VA_IN_TB B
ON REPLACE(A.PRODUCT_NAME,'''','')= REPLACE(B.PRODUCT_NAME,'''','')
AND A.PID BETWEEN LWR_LMT AND UPR_LMT
union all
select A.PID,
B.PRODUCT_ID,
B.SEQ_ID,
PRICE VALUE
from PRODUCT_TABLE A
JOIN VA_IN_TB B
ON REPLACE(A.COMPANY_NM,'''','')=REPLACE(B.PRODUCT_NAME,'''','') ----Seems Not correct.
AND A.PID BETWEEN LWR_LMT AND UPR_LMT
) A
LEFT JOIN VA_TB B
ON A.PRODUCT_ID = B.PRODUCT_ID
) A
LEFT JOIN VA_TB B
ON A.TYPE_NAME = B.PRODUCT_NAME ; ----Seems Not correct.
type var is table of cur_rec%rowtype;
var_order_tab var;
begin
/**Procedure will fail if you try to do anything like this**/
---REC_COUNT:= SELECT COUNT(*) FROM PRODUCT_TABLE;
SELECT COUNT(*)
into REC_COUNT
FROM PRODUCT_TABLE;
Loop_CT :=( REC_COUNT/2000000)+1;
SELECT MIN(PID)
INTO LOWER_LIMIT
FROM PRODUCT_TABLE;
UPPER_LIMIT := LOWER_LIMIT +2000000;
Open cur_rec(LOWER_LIMIT,UPPER_LIMIT);
loop
fetch cur_rec bulk collect into var_order_tab limit 100;
FORALL i IN 1 .. var_order_tab.count
INSERT INTO ORDER_TB
VALUES var_order_tab(i);
commit;
end loop;
close cur_rec ;
/**** You cannot create any table like this in any procedure. This is not allowed in PLSQL.
FOR i in 1..LOOP_COUNT LOOP
Create Table Temp_1 Nologging as
SELECT ORDER_SEQ.NEXTVAL OID,
A.PID,A.PRODUCT_ID,
A.SEQ_ID,
A.VALUE,
B.TYPE_ID
FROM
(
SELECT A.PID,
A.VA_ID,
A.SEQ_ID,
A.VALUE,
B.TYPE_NAME
FROM
(
select A.PID,
B.PRODUCT_ID,
B.SEQ_ID,
PRODUCT_NAME VALUE
from PRODUCT_TABLE A
JOIN VA_IN_TB B
ON REPLACE(A.PRODUCT_NAME,'''','')=REPLACE(B.COL_NM,'''','')
AND A.PID BETWEEN LOWER_LIMIT AND UPPER_LIMIT
union all
select A.PID,
B.PRODUCT_ID,
B.SEQ_ID,
PRICE VALUE
from PRODUCT_TABLE A
JOIN VA_IN_TB B
ON REPLACE(A.COMPANY_N,'''','')=REPLACE(B.COL_NM,'''','')
AND A.PID BETWEEN LOWER_LIMIT AND UPPER_LIMIT
) A
LEFT JOIN VA_TB B
ON A.PRODUCT_ID=B.PRODUCT_ID
) A
LEFT JOIN VA_TB B
ON A.TYPE_NAME=B.PRODUCT_NAME ****/
--Insert INTO ORDER_TB
--SELECT * FROM TEMP_1;
--Commit;
/****Neither executing drop command directly is permitted***/
--DROP TABLE TEMP_1;
LOWER_LIMIT := UPPER_LIMIT + 1;
UPPER_LIMIT := UPPER_LIMIT + 2000000;
--End LOOP;
end;
答案 1 :(得分:0)
您可以将数据选择到临时表中,然后将临时表的内容复制到表中。为什么不直接在表格中选择数据?
Insert INTO ORDER_TB
select order_seq.nextval oid
,a.pid
,a.product_id
,a.seq_id
,a.value
,b.type_id
from (select a.pid
,a.va_id
,a.seq_id
,a.value
,b.type_name
from (select a.pid
,b.product_id
,b.seq_id
,product_name value
from product_table a
join va_in_tb b
on replace(a.product_name, '''', '') = replace(b.col_nm, '''', '')
and a.pid between lower_limit and upper_limit
union all
select a.pid
,b.product_id
,b.seq_id
,price value
from product_table a
join va_in_tb b
on replace(a.company_n, '''', '') = replace(b.col_nm, '''', '')
and a.pid between lower_limit and upper_limit) a
left join va_tb b
on a.product_id = b.product_id) a
left join va_tb b
on a.type_name = b.product_name