Oracle PLSQL过程需要很长时间才能执行
我创建了下面的过程,在添加粗体代码之前运行得很好。现在它一次插入100条记录。已经一个多小时了,它只插入了4000条记录。有200万条记录需要插入。我有没有办法加快执行Oracle PLSQL过程需要很长时间才能执行,oracle,stored-procedures,plsql,Oracle,Stored Procedures,Plsql,我创建了下面的过程,在添加粗体代码之前运行得很好。现在它一次插入100条记录。已经一个多小时了,它只插入了4000条记录。有200万条记录需要插入。我有没有办法加快执行 create or replace PROCEDURE LOAD_ADDRESS_PROCEDURE AS CNTY varchar2(100); ST varchar2(100); createdby_value varchar2(50); **defaultAddress_value varchar2(1);**
create or replace PROCEDURE LOAD_ADDRESS_PROCEDURE AS
CNTY varchar2(100);
ST varchar2(100);
createdby_value varchar2(50);
**defaultAddress_value varchar2(1);**
CURSOR C1 is
SELECT ADDRESS, CITY, STATE, ZIP, COUNTRY, seasonal_start_day, seasonal_start_month, seasonal_end_day, seasonal_end_month, key_address_id, key_account_id, BAD_ADDRESS,
CREATED, CREATED_BY, address_type,
(select siebel_country_name from STATE_AND_COUNTRY_VALUES_LIST where s.COUNTRY IS NULL and s.state = siebel_state_abbreviation) newCNTY,
(select SF_COUNTRY_ABBREVIATION FROM STAGE_COUNTRY WHERE SIEBEL_COUNTRY = s.Country) newCountry,
(select SF_COUNTRY_ABBREVIATION FROM STAGE_COUNTRY
WHERE SIEBEL_COUNTRY = (select siebel_country_name from STATE_AND_COUNTRY_VALUES_LIST where s.COUNTRY IS NULL and s.state = siebel_state_abbreviation)) newCountry1,
(SELECT SIEBEL_LOGIN from STAGE_USER where KEY_USER_ID = s.CREATED_BY) SiebelLogin,
(SELECT SALESFORCE_USER from STAGE_USER where KEY_USER_ID = s.CREATED_BY) SFUSER,
(SELECT KEY_USER_ID from STAGE_USER where KEY_USER_ID = s.CREATED_BY) KeyUserID,
**(SELECT KEY_PRIMARY_ADDRESS_ID FROM STAGE_ACCOUNT WHERE KEY_PRIMARY_ADDRESS_ID = s.KEY_ADDRESS_ID) defaultAddress**
FROM STAGE_ADDRESS s;
BEGIN
FOR i IN C1 LOOP
ST := i.state;
CNTY := i.country;
/*if(i.newCountry = i.newCNTY) then*/
/*if (i.country is null) then
CNTY := i.newCountry1;
end if;
comment end*/
if (i.state = 'NA') then
ST := NULL;
end if;
/*end if;*/
/*
if(CNTY != i.newCountry) then
CNTY := i.newCountry;
end if;
if(i.newCountry is null) then
CNTY := NULL;
end if;
comment end*/
IF(CNTY IS NULL) THEN
CNTY := i.newCountry1;
ELSE
CNTY := i.newCountry;
END IF;
IF(i.CREATED_BY = i.KeyUserID AND i.SFUSER = 'MIGRATIONUSER') THEN
createdby_value := 'MIGRATIONUSER';
ELSE
createdby_value := i.KeyUserID;
END IF;
**IF(i.defaultAddress IS NOT NULL) THEN
defaultAddress_value := 'Y';
ELSE
defaultAddress_value := 'N';
END IF;**
INSERT INTO LOAD_ADDRESS(NPSP__MAILINGSTREET__C, NPSP__MAILINGCITY__C, NPSP__MAILINGSTATE__C, NPSP__MAILINGPOSTALCODE__C, NPSP__MAILINGCOUNTRY__C, NPSP__SEASONAL_START_DAY__C,
NPSP__SEASONAL_START_MONTH__C, NPSP__SEASONAL_END_DAY__C, NPSP__SEASONAL_END_MONTH__C, ERP_EXTERNAL_ID_C, NPSP__HOUSEHOLD_ACCOUNT__C, ADDRESS_STATUS_OVERRIDE, CREATED,
CREATED_BY, NPSP_ADDRESS_TYPE_C, **NPSP__DEFAULT_ADDRESS__C**) VALUES
(i.ADDRESS, REGEXP_REPLACE(i.CITY, '|||||', ' '), ST, i.ZIP, CNTY, i.seasonal_start_day, i.seasonal_start_month, i.seasonal_end_day, i.seasonal_end_month, i.key_address_id, i.key_account_id,
DECODE(i.BAD_ADDRESS,'Y','1','N','0'), i.CREATED, createdby_value, i.address_type, **defaultAddress_value**);
COMMIT;
END LOOP;
END LOAD_ADDRESS_PROCEDURE;
我建议你完全重写选择。您可能应该对STAGE\u USER、STAGE\u COUNTRY和查询使用的任何其他表使用联接 有一些IFs可以(至少,我希望如此)通过使用CASE(或DECODE)重写,这将使使用快速SQL(直接插入)而不是慢速PL/SQL(在循环中)成为可能
顺便说一句,您正在循环内提交-删除外部提交。我建议您完全重写选择。您可能应该对STAGE\u USER、STAGE\u COUNTRY和查询使用的任何其他表使用联接 有一些IFs可以(至少,我希望如此)通过使用CASE(或DECODE)重写,这将使使用快速SQL(直接插入)而不是慢速PL/SQL(在循环中)成为可能
顺便说一句,您正在循环内提交-在循环外删除提交。您可以重写您的过程,在单个insert语句中执行所有逻辑,例如:
INSERT INTO load_address
(npsp__mailingstreet__c,
npsp__mailingcity__c,
npsp__mailingstate__c,
npsp__mailingpostalcode__c,
npsp__mailingcountry__c,
npsp__seasonal_start_day__c,
npsp__seasonal_start_month__c,
npsp__seasonal_end_day__c,
npsp__seasonal_end_month__c,
erp_external_id_c,
npsp__household_account__c,
address_status_override,
created,
created_by,
npsp_address_type_c,
npsp__default_address__c)
SELECT address,
regexp_replace(i.city, '|||||', ' '),
CASE
WHEN state = 'NA' THEN
NULL
ELSE
state
END state,
zip,
CASE
WHEN country IS NULL THEN
newcountry1
ELSE
newcountry
END country,
seasonal_start_day,
seasonal_start_month,
seasonal_end_day,
seasonal_end_month,
key_address_id,
key_account_id,
DECODE(bad_address, 'Y', '1', 'N', '0'),
created,
CASE
WHEN created_by = keyuserid
AND sfuser = 'MIGRATIONUSER' THEN
sfuser
ELSE
keyuserid
END createdby_value,
address_type,
CASE
WHEN default_address IS NOT NULL THEN
'Y'
ELSE
'N'
END defaultaddress_value
FROM (SELECT address,
city,
state,
zip,
country,
seasonal_start_day,
seasonal_start_month,
seasonal_end_day,
seasonal_end_month,
key_address_id,
key_account_id,
bad_address,
created,
created_by,
address_type,
(SELECT siebel_country_name
FROM state_and_country_values_list
WHERE s.country IS NULL
AND s.state = siebel_state_abbreviation) newcnty,
(SELECT sf_country_abbreviation
FROM stage_country
WHERE siebel_country = s.country) newcountry,
(SELECT sf_country_abbreviation
FROM stage_country
WHERE siebel_country = (SELECT siebel_country_name
FROM state_and_country_values_list
WHERE s.country IS NULL
AND s.state = siebel_state_abbreviation)) newcountry1,
su.siebel_login siebellogin,
su.salesforce_user sfuser,
su.key_user_id keyuserid,
(SELECT key_primary_address_id
FROM stage_account
WHERE key_primary_address_id = s.key_address_id) defaultaddress
FROM stage_address s
LEFT OUTER JOIN stage_user su ON s.created_by = su.key_user_id);
我已经将status_user上的标量子查询移动到外部联接,因为联接可能比查询同一个表3次更有效。您可能可以对其他标量子查询执行类似的操作(即,将它们组合成两个连接或其他操作),但我将其留给您使用。您可以重写过程,在单个insert语句中执行所有逻辑,例如:
INSERT INTO load_address
(npsp__mailingstreet__c,
npsp__mailingcity__c,
npsp__mailingstate__c,
npsp__mailingpostalcode__c,
npsp__mailingcountry__c,
npsp__seasonal_start_day__c,
npsp__seasonal_start_month__c,
npsp__seasonal_end_day__c,
npsp__seasonal_end_month__c,
erp_external_id_c,
npsp__household_account__c,
address_status_override,
created,
created_by,
npsp_address_type_c,
npsp__default_address__c)
SELECT address,
regexp_replace(i.city, '|||||', ' '),
CASE
WHEN state = 'NA' THEN
NULL
ELSE
state
END state,
zip,
CASE
WHEN country IS NULL THEN
newcountry1
ELSE
newcountry
END country,
seasonal_start_day,
seasonal_start_month,
seasonal_end_day,
seasonal_end_month,
key_address_id,
key_account_id,
DECODE(bad_address, 'Y', '1', 'N', '0'),
created,
CASE
WHEN created_by = keyuserid
AND sfuser = 'MIGRATIONUSER' THEN
sfuser
ELSE
keyuserid
END createdby_value,
address_type,
CASE
WHEN default_address IS NOT NULL THEN
'Y'
ELSE
'N'
END defaultaddress_value
FROM (SELECT address,
city,
state,
zip,
country,
seasonal_start_day,
seasonal_start_month,
seasonal_end_day,
seasonal_end_month,
key_address_id,
key_account_id,
bad_address,
created,
created_by,
address_type,
(SELECT siebel_country_name
FROM state_and_country_values_list
WHERE s.country IS NULL
AND s.state = siebel_state_abbreviation) newcnty,
(SELECT sf_country_abbreviation
FROM stage_country
WHERE siebel_country = s.country) newcountry,
(SELECT sf_country_abbreviation
FROM stage_country
WHERE siebel_country = (SELECT siebel_country_name
FROM state_and_country_values_list
WHERE s.country IS NULL
AND s.state = siebel_state_abbreviation)) newcountry1,
su.siebel_login siebellogin,
su.salesforce_user sfuser,
su.key_user_id keyuserid,
(SELECT key_primary_address_id
FROM stage_account
WHERE key_primary_address_id = s.key_address_id) defaultaddress
FROM stage_address s
LEFT OUTER JOIN stage_user su ON s.created_by = su.key_user_id);
我已经将status_user上的标量子查询移动到外部联接,因为联接可能比查询同一个表3次更有效。您可能可以对其他标量子查询执行类似的操作(即,将它们组合成两个联接或其他操作),但我将其留给您使用。表
STAGE\u ACCOUNT
中有多少记录?是否有任何类型的索引建立在它的基础上?为什么不将此过程替换为一个插入到。。。(选择…)
?您的代码就是一个典型的示例。您的选择非常难看和糟糕。我从来没有使用过像SELECT…,(SELECT…,FROM…)这样的表达式。。。从…
开始,在我的生活中写了数千条select语句。使用连接
,最有可能的是外部连接
。我没有详细检查逻辑,但我假设它可以在单个INSERT-INTO-LOAD\u-ADDRESS(…)选择中不使用任何循环完成代码>-最多两个。@Wernfrieddomsheit真的吗?您以前从未使用过标量子查询?他们一点也不丑陋;事实上,由于标量子查询缓存,它们(在某些情况下)可以提高性能,使它们成为存储在SQL工具箱中的极好工具!表STAGE\u ACCOUNT
中有多少条记录?是否有任何类型的索引建立在它的基础上?为什么不将此过程替换为一个插入到。。。(选择…)
?您的代码就是一个典型的示例。您的选择非常难看和糟糕。我从来没有使用过像SELECT…,(SELECT…,FROM…)这样的表达式。。。从…
开始,在我的生活中写了数千条select语句。使用连接
,最有可能的是外部连接
。我没有详细检查逻辑,但我假设它可以在单个INSERT-INTO-LOAD\u-ADDRESS(…)选择中不使用任何循环完成代码>-最多两个。@Wernfrieddomsheit真的吗?您以前从未使用过标量子查询?他们一点也不丑陋;事实上,由于标量子查询缓存,它们(在某些情况下)可以提高性能,使它们成为存储在SQL工具箱中的极好工具!注意,我在一些查询和列中留下了一些在您的过程中似乎未使用过的内容,以防您在实际代码中需要它们。但是,如果您的代码不需要它们(例如,在您最初的过程中,newcnty
列在光标之外的任何位置都不会被引用。Oracle很可能会从insert as select语句中筛选出该列,但如果我是您,我会删除任何不必要的子查询;这样您就知道您的查询肯定没有做不必要的工作。注意,我在一些e查询和列,这些查询和列在您的过程中似乎未被使用,以防您在实际代码中需要它们(例如,在您的原始过程中,newcnty
列不会在光标之外的任何位置引用。Oracle很可能会从insert as select语句中筛选出该列,但如果我是您,我会删除任何不必要的子查询;这样您就知道您的查询肯定没有做不必要的工作。