Oracle PLSQL过程需要很长时间才能执行

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);**

我创建了下面的过程,在添加粗体代码之前运行得很好。现在它一次插入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);**

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语句中筛选出该列,但如果我是您,我会删除任何不必要的子查询;这样您就知道您的查询肯定没有做不必要的工作。