执行以下存储过程时需要20分钟。预计时间为2-3分钟。 为什么会这样? 谁能告诉我为什么这个sp花了这么多时间?可以做些什么来让它跑得更快? 非常感谢提前。这个程序的逻辑是,它检查表中是否存在订单号,如果没有则插入该表
CREATE OR REPLACE PROCEDURE sp_load_order
IS
l_ds_ds_id data_source.ds_id%TYPE;
l_carrier stage_na_shipment.haulier_name%TYPE;
l_vehicle_number stage_na_shipment.haulier_num%TYPE;
l_ship_date stage_na_shipment.ship_date`enter code here`%TYPE;
l_source_key VARCHAR2 (20);
l_source_key_1 VARCHAR2 (20);
l_quantity stage_na_shipment.quantity%TYPE;
l_ship_from stage_na_shipment.ship_from%TYPE;
l_prod_prod_id product.prod_prod_id%TYPE;
l_client stage_na_shipment.client%TYPE;
l_ord_id ordr.ord_id%TYPE;
l_sf_sf_id ship_from.sf_id%TYPE;
l_cust_cust_id customer.cust_cust_id%TYPE;
l_ord_stat_ord_stat_id ordr_status.ord_stat_id%TYPE;
l_le_le_id legal_entity.le_id%TYPE;
l_mkt_mkt_id market.mkt_id%TYPE;
l_code bill_type.code%TYPE;
l_ord_ord_id ordr.ord_id%TYPE;
l_ord_prod_id ordr_product.ord_prod_id%TYPE;
l_po_number stage_na_shipment.po_number%TYPE;
l_expct_ship_date stage_na_shipment.ship_date%TYPE;
l_bt_bt_id bill_type.bt_id%TYPE;
l_order_process_date stage_na_shipment.ship_date%TYPE;
l_storage_loc stage_na_shipment.stor_loc%TYPE;
l_ship_unit_code_8 stage_na_shipment.ship_unit_code_8%TYPE;
l_del_point stage_na_shipment.DEL_POINT%type;
l_r_num NUMBER;
n_1 NUMBER;
l_error_msg VARCHAR2 (500);
start_time timestamp;
end_time timestamp;
BEGIN
start_time:=systimestamp;
DBMS_OUTPUT.put_line ('Procedure started' ||start_time);
sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', 'START', NULL, NULL, NULL);
start_time:=systimestamp;
DBMS_OUTPUT.put_line ('DS_ID start_time' ||start_time);
SELECT ds_id
INTO l_ds_ds_id
FROM data_source
WHERE ds_id = 1;
DBMS_OUTPUT.put_line ('DS_ID' || l_ds_ds_id);
end_time:=systimestamp;
DBMS_OUTPUT.put_line ('DS_ID start_time' ||end_time);
start_time:=systimestamp;
DBMS_OUTPUT.put_line ('ord_stat_id start_time' ||start_time);
SELECT ord_stat_id
INTO l_ord_stat_ord_stat_id
FROM ordr_status
WHERE ord_stat_id = 2;
DBMS_OUTPUT.put_line ('ORD_STAT_ID' || l_ord_stat_ord_stat_id);
end_time:=systimestamp;
DBMS_OUTPUT.put_line ('ORD_STAT_ID end_time' ||end_time);
start_time:=systimestamp;
DBMS_OUTPUT.put_line ('le_id start_time' ||start_time);
SELECT le_id
INTO l_le_le_id
FROM legal_entity
WHERE le_id = 1;
DBMS_OUTPUT.put_line ('LE_ID' || l_le_le_id);
end_time:=systimestamp;
DBMS_OUTPUT.put_line ('LE_ID end_time' ||end_time);
SELECT COUNT (*)
INTO l_r_num
FROM frontroom.ordr;
sp_log_entry (SYSDATE,
'SP_LOAD_ORDER',
'MESSAGE',
'FRONTROOM_BEF_INS',
l_r_num,
NULL
);
SELECT COUNT (*)
INTO l_r_num
FROM frontroom.ordr_product;
sp_log_entry (SYSDATE,
'SP_LOAD_ORDER',
'MESSAGE',
'ORDRPRODUCT_BEFORE_INS',
l_r_num,
NULL
);
DBMS_OUTPUT.put_line ('loop started' ||start_time);
FOR i IN (SELECT order_num_cos, ship_date, haulier_name, haulier_num,
po_number, stor_loc, ship_unit_code, ship_unit_code_8,
so_item, ship_from, del_point, currency, client, quantity
FROM stage_na_shipment)
LOOP
l_source_key := TO_CHAR (i.order_num_cos);
l_carrier := TO_CHAR (i.haulier_name);
l_vehicle_number := TO_CHAR (i.haulier_num);
l_source_key_1 := TO_CHAR (i.order_num_cos || i.so_item);
l_po_number := i.po_number;
l_storage_loc := TO_CHAR (i.stor_loc);
l_del_point :=i.del_point;
l_ship_date := i.ship_date;
l_ship_from := TO_CHAR (i.ship_from);
l_ship_unit_code_8 := TO_CHAR (i.ship_unit_code_8);
l_client := TO_CHAR (i.client);
DBMS_OUTPUT.put_line ('order_number' || i.order_num_cos);
BEGIN
start_time:=systimestamp;
DBMS_OUTPUT.put_line ('mkt_id start_time' ||start_time);
SELECT mkt_id INTO l_mkt_mkt_id
FROM market
WHERE code = DECODE (SUBSTR (l_client, 1, 4), 'US23', 'MM',
'US99', 'AFFCO' );
DBMS_OUTPUT.put_line ('MKT_ID' || l_mkt_mkt_id);
EXCEPTION
WHEN NO_DATA_FOUND
THEN
sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', NULL, 'THE MKT ID NOT FOUND :',
NULL, NULL );
GOTO end_loop;
WHEN TOO_MANY_ROWS THEN
sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', NULL, 'MKT ID TWO MANY ROWS FOUND :'||i.order_num_cos,
NULL, NULL );
WHEN others
THEN
sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', NULL, SQLERRM, NULL, NULL );
END;
end_time:=systimestamp;
DBMS_OUTPUT.put_line ('mkt_id end_time' ||end_time);
start_time:=systimestamp;
DBMS_OUTPUT.put_line ('bt_id start_time' ||start_time);
BEGIN
IF i.quantity >= 0
THEN
l_code := 'O';
ELSE
l_code := 'C';
END IF;
SELECT bt_id INTO l_bt_bt_id FROM bill_type
WHERE code = l_code
AND ds_ds_id = l_ds_ds_id;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
sp_log_entry
(SYSDATE,
'SP_LOAD_ORDER',
NULL,
'BILL TYPE ID NOT FOUND',
NULL,
NULL
);
GOTO end_loop;
WHEN TOO_MANY_ROWS THEN
sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', NULL, 'BILL TYPE ID TWO MANY ROWS FOUND :'||i.order_num_cos,
NULL, NULL );
WHEN others
THEN
sp_log_entry (SYSDATE,
'SP_LOAD_ORDER',
NULL,
SQLERRM,
NULL,
NULL
);
END;
DBMS_OUTPUT.put_line ('BT_ID :' || l_bt_bt_id);
end_time:=systimestamp;
DBMS_OUTPUT.put_line ('BT_ID end_time' ||end_time);
start_time:=systimestamp;
DBMS_OUTPUT.put_line ('prod_id start_time' ||start_time);
BEGIN
SELECT prod_prod_id
INTO l_prod_prod_id
FROM product
WHERE secondary_source_key = LTRIM (l_ship_unit_code_8, 0);
EXCEPTION
WHEN NO_DATA_FOUND
THEN
sp_log_entry (SYSDATE,
'SP_LOAD_ORDER',
NULL,
'THE PRODUCT ID ' ||i.ship_unit_code_8 ||' could not be found in product table :',
'order_num_cos = ' || i.order_num_cos
,
NULL
);
GOTO end_loop;
WHEN TOO_MANY_ROWS THEN
sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', NULL, 'THE PRODUCT ID TWO MANY ROWS FOUND :' ||i.order_num_cos,
NULL, NULL );
WHEN OTHERS
THEN
sp_log_entry (SYSDATE,
'SP_LOAD_ORDER',
NULL,
SQLERRM,
i.ship_unit_code_8 || SQLERRM,
NULL
);
END;
DBMS_OUTPUT.put_line (' PROD_PROD_ID :' || l_prod_prod_id);
end_time:=systimestamp;
DBMS_OUTPUT.put_line ('PROD_ID end_time' ||end_time);
start_time:=systimestamp;
DBMS_OUTPUT.put_line ('sf_id start_time' ||start_time);
BEGIN
SELECT sf_id
INTO l_sf_sf_id
FROM ship_from
WHERE source_key = l_ship_from;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
sp_log_entry (SYSDATE,
'SP_LOAD_ORDER',
NULL,
'sf_id NOT FOUND',
NULL,
NULL
);
GOTO end_loop;
WHEN TOO_MANY_ROWS THEN
sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', NULL, 'sf_id TWO MANY ROWS FOUND :'||i.order_num_cos,
NULL, NULL );
WHEN others
THEN
sp_log_entry (SYSDATE,
'SP_LOAD_ORDER',
NULL,
SQLERRM,
NULL,
NULL
);
END;
DBMS_OUTPUT.put_line ('SF_ID :' || l_sf_sf_id);
end_time:=systimestamp;
DBMS_OUTPUT.put_line ('sf_id end_time' ||end_time);
start_time:=systimestamp;
DBMS_OUTPUT.put_line ('cust_id start_time' ||start_time);
BEGIN
SELECT cust_id
INTO l_cust_cust_id
FROM customer
WHERE true_gcdb_source_key = to_char(i.del_point);
-- AND ds_ds_id = l_ds_ds_id;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
sp_log_entry (SYSDATE,
'SP_LOAD_ORDER',
NULL,
'THE CUST ID ' || l_del_point || 'COULD NOT BE FOUND IN THE CUSTOMER TABLE''order_num_cos = '||i.order_num_cos,
NULL,
NULL
);
GOTO end_loop;
WHEN TOO_MANY_ROWS THEN
sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', NULL, 'cust_id TWO MANY ROWS FOUND :'||i.order_num_cos,
NULL, NULL );
WHEN others
THEN
sp_log_entry (SYSDATE,
'SP_LOAD_ORDER',
NULL,
SQLERRM,
NULL,
NULL
);
END;
DBMS_OUTPUT.put_line ('CUST_ID :' || l_cust_cust_id);
end_time:=systimestamp;
DBMS_OUTPUT.put_line ('CUST_ID end_time' ||end_time);
start_time:=systimestamp;
DBMS_OUTPUT.put_line ('INSERTING INTO frontroom.ordr' ||start_time);
BEGIN
INSERT INTO frontroom.ordr
(ord_number, ds_ds_id, erlst_ship_dt, carrier,
vehicle_number, ord_dt, source_key, sf_sf_id,
cust_cust_id, ord_stat_ord_stat_id, le_le_id,
mkt_mkt_id, sc_sc_id, ctrl_dt, po_number,
expct_ship_date, bt_bt_id, order_process_dt,
storage_loc)
SELECT l_source_key, l_ds_ds_id, i.ship_date, l_carrier,
l_vehicle_number, i.ship_date, l_source_key, l_sf_sf_id,
l_cust_cust_id, l_ord_stat_ord_stat_id, l_le_le_id,
l_mkt_mkt_id, 0, i.ship_date, l_po_number, i.ship_date,
l_bt_bt_id, i.ship_date, l_storage_loc
FROM DUAL
WHERE NOT EXISTS (SELECT 1--ord_number
FROM frontroom.ordr
WHERE ord_number = l_source_key);
EXCEPTION
WHEN OTHERS
THEN
l_error_msg := SQLERRM;
sp_log_entry (SYSDATE,
'SP_LOAD_ORDER',
NULL,
l_error_msg,
'order_num_cos = ' || i.order_num_cos,
NULL
);
GOTO end_loop;
END;
DBMS_OUTPUT.put_line ('Inserted into order table');
end_time:=systimestamp;
DBMS_OUTPUT.put_line ('Inserted into order table' ||end_time);
SELECT ord_id
INTO l_ord_ord_id
FROM frontroom.ordr
WHERE ord_number = l_source_key;
start_time:=systimestamp;
DBMS_OUTPUT.put_line ('INSERTING INTO frontroom.ordr_product' ||start_time);
BEGIN
INSERT INTO ordr_product
(volume, revenue, source_key, ord_ord_id, prod_prod_id,
local_currency)
SELECT i.ship_unit_code, 0, l_source_key_1, l_ord_ord_id,
l_prod_prod_id, i.currency
FROM DUAL
WHERE NOT EXISTS (
SELECT 1--ord_ord_id
FROM ordr_product
WHERE ord_ord_id =
(SELECT ord_id
FROM ordr
WHERE ord_number = l_source_key));
EXCEPTION
WHEN OTHERS
THEN
l_error_msg := SQLERRM;
sp_log_entry (SYSDATE,
'SP_LOAD_ORDER',
NULL,
l_error_msg,
'order_num_cos = ' || i.order_num_cos,
NULL
);
GOTO end_loop;
END;
n_1 := n_1 + 1;
if n_1 = 100 then
COMMIT;
n_1 := 0;
end if;
<<end_loop>>
null;
END LOOP;
end_time:=systimestamp;
DBMS_OUTPUT.put_line ('Inserted into order table' ||end_time);
end_time:=systimestamp;
DBMS_OUTPUT.put_line ('Loop ends' ||end_time);
SELECT COUNT (*)
INTO l_r_num
FROM frontroom.ordr;
sp_log_entry (SYSDATE,
'SP_LOAD_ORDER',
'MESSAGE',
'FRONTROOM_AFTER_INS',
l_r_num,
NULL
);
SELECT COUNT (*)
INTO l_r_num
FROM frontroom.ordr_product;
sp_log_entry (SYSDATE,
'SP_LOAD_ORDER',
'MESSAGE',
'ORDRPRODUCT_AFTER_INS',
l_r_num,
NULL
);
sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', 'COMPLETE', NULL, NULL, NULL);
end_time:=systimestamp;
DBMS_OUTPUT.put_line ('Procedure ends' ||end_time);
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
l_error_msg := SQLERRM;
sp_log_entry (SYSDATE, 'SP_LOAD_ORDER', NULL, l_error_msg, NULL, NULL);
END sp_load_order;
/
答案 0 :(得分:2)
幸运的是,你正在使用PL / SQL Developer,这使得PL / SQL分析非常容易。
sp_load_order;
添加到中间。然后你会确切知道程序的哪些行很慢。
答案 1 :(得分:1)
在不知道数据库的情况下,很难弄清问题是什么,尤其是像这样的大型程序。
但是你可以考虑一些事情:
您正在循环中执行DML(插入),通常使用批量操作可以获得相当大的性能提升。欲了解更多信息,请查看:http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/tuning.htm#i48876 可在此处找到更“用户友好”的说明:http://www.oracle-base.com/articles/9i/bulk-binds-and-record-processing-9i.php 请注意,如果您不熟悉批量操作,首先要破解它可能是一个难题。
在做任何激烈的事情之前(问题可能像缺失的索引一样简单)你可以先跟踪它来分析问题。
要做到这一点,首先必须启动te程序,并使用此查询(来自另一个会话)找出它的会话ID和序列号:
select username, status, sid, serial# from v$session
完成后,您可以使用以下命令启动跟踪:
exec dbms_monitor.session_trace_enable(session_id=>3,serial_num=>5027,binds=>true,waits=>true);
程序完成后,您可以停止跟踪:
exec dbms_monitor.session_trace_disable(session_id=>3,serial_num=>5027);
Oracle现在已经编写了一些跟踪文件,以确定oracle放置它们的位置,执行此命令:
SELECT VALUE FROM V$DIAG_INFO WHERE NAME = 'Default Trace File';
跟踪文件的可读性不是很高,但您可以使用tkprof命令行实用程序获取可读报告。您可以从命令行运行if:
tkprof <source trace file> <output file>
现在,您将拥有一个包含已在其中运行的所有查询的文件,并且每个报告一个这样的表格:
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 9 0.00 0.00 0 0 0 0
Execute 9 0.00 0.01 1 32 0 1
Fetch 3 0.00 0.00 0 32 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 21 0.00 0.01 1 64 0 2
通过这种方式,您可以找出查询时间最长的查询。 你也可以从中获得这样的信息,它可以告诉你已运行的查询数量:
1 session in tracefile.
9 user SQL statements in trace file.
2 internal SQL statements in trace file.
11 SQL statements in trace file.
10 unique SQL statements in trace file.
504 lines in trace file.
4 elapsed seconds in trace file.
提供