我的一个存储过程最近花费了大约6个小时,通常需要大约3个小时才能完成。
检查时,我发现游标正在花时间执行。
这两个表都在我的本地数据库实例中。
我需要知道这可能是什么原因以及如何对程序进行微调。
melt
答案 0 :(得分:1)
首先,DDL具有隐式提交,因此在放置表之后不需要提交。 其次,为什么要删除表并重新创建它,而不仅仅是截断表并插入其中? 第三,当可以在单个update语句中进行更新时,为什么要围绕游标进行更新?
如果您绝对必须将数据存储在单独的表中,我将像这样重写您的过程:
CREATE OR REPLACE PROCEDURE vms_details_d_1 IS
log_d1 VARCHAR2(20);
BEGIN
/* IDENTIFY PARTITION */
SELECT partition_name
INTO log_d1
FROM all_tab_partitions a
WHERE table_name = 'LOG'
AND table_owner = 'OWNER1'
AND partition_position IN (SELECT MAX(partition_position - 1)
FROM all_tab_partitions b
WHERE table_name = a.table_name
AND a.table_owner = b.table_owner);
EXECUTE IMMEDIATE 'TRUNCATE TABLE TAB1 reuse storage';
EXECUTE IMMEDIATE 'insert into TAB1 (transactionid, time_stamp)'||CHR(10)||
'select /*+ Parallel(20) */ TRANSACTIONID,TIME_STAMP from OWNER1.log partition(' || log_d1 || ')'||CHR(10)||
'where MESSAGE in (''WalletUpdate| Request for Estel Update is Processed'', ''Voucher Core request processed'')';
EXECUTE IMMEDIATE 'CREATE INDEX IDX_TAB1 on TAB1(TRANSACTIONID)';
dbms_stats.gather_table_stats(ownname => 'OWNER2',
tabname => 'TAB1',
cascade => TRUE,
estimate_percent => 10,
method_opt => 'for all indexed columns size 1',
granularity => 'ALL',
degree => 1);
MERGE INTO tab2 tgt
USING (SELECT transactionid,
max(time_stamp) ts
FROM tab1
GROUP BY transactionid) src
ON (tgt.transactionid = src.transactionid)
WHEN MATCHED THEN
UPDATE SET tgt.tctime = to_char(src.ts, 'dd-mm-yyyy hh24:mi:ss'); -- is tab2.tctime really a string? If it's a date, remove the to_char
COMMIT;
END vms_details_d_1;
/
如果只是复制数据以使其更容易进行更新,则不需要-相反,您可以在单个DML语句中完成所有操作,例如:
CREATE OR REPLACE PROCEDURE vms_details_d_1 IS
log_d1 VARCHAR2(20);
BEGIN
/* IDENTIFY PARTITION */
SELECT partition_name
INTO log_d1
FROM all_tab_partitions a
WHERE table_name = 'LOG'
AND table_owner = 'OWNER1'
AND partition_position IN (SELECT MAX(partition_position - 1)
FROM all_tab_partitions b
WHERE table_name = a.table_name
AND a.table_owner = b.table_owner);
EXECUTE IMMEDIATE 'MERGE INTO tab2 tgt'||CHR(10)||
' USING (SELECT transactionid,'||CHR(10)||
' MAX(time_stamp) ts'||CHR(10)||
' FROM owner1.log partition(' || log_d1 || ')'||CHR(10)||
' GROUP BY transactionid) src'||CHR(10)||
' ON (tgt.transactionid = src.transactionid)'||CHR(10)||
'WHEN MATCHED THEN'||CHR(10)||
' UPDATE SET tgt.tctime = to_char(src.ts, ''dd-mm-yyyy hh24:mi:ss'')'; -- is tab2.tctime really a string? If it's a date, remove the to_char
COMMIT;
END vms_details_d_1;
/
如果知道定义所要分区的谓词,则可以在查询中使用这些谓词,从而无需查找分区名称,因此不需要动态SQL。
答案 1 :(得分:0)
好的,您的程序需要很多增强:
在下面的查询中,您可以使用user_tab_partitions
代替all_tab_partitions
。
选择partition_name 进入LOG_D1 从all_tab_partitions一个 WHERE table_name ='LOG' AND TABLE_OWNER ='OWNER1' 和partition_position IN (SELECT MAX(分区位置-1) 从all_tab_partitions b WHERE table_name = a.table_name AND a.table_owner = b.table_owner);
您必须在表tab1上进行检查,以防它不存在并且不需要在此处提交,它不是DML语句。
立即执行“ DROP TABLE TAB1 PURGE”; 承诺;
以上内容可能会稍微改善性能,但是您必须检查表日志中是否有用于列消息的索引(但正如我所说的错误建模),还需要检查tab2上的查询计划是否需要索引。
答案 2 :(得分:0)
这是错误的方法,您正在执行的是更新TAB2游标resp_cur中的记录的次数,我将切换到合并。