oracle 存储过程更新表列花费的时间太长

ztmd8pv5  于 2023-02-03  发布在  Oracle
关注(0)|答案(2)|浏览(120)

我创建了一个存储过程,它花费了太多的时间来更新表中的列。假设3小时更新43k条记录中的2.5k条记录。
这样我就可以减少更新记录的时间。下面是我的逻辑。

procedure UPDATE_MST_INFO_BKC
  (
    P_SAPID IN NVARCHAR2
  )
  as
  v_cityname varchar2(500):='';
  v_neid varchar2(500):='';
  v_latitude varchar2(500):='';
  v_longitude varchar2(500):='';
  v_structuretype varchar2(500):='';
  v_jc_name varchar2(500):='';
  v_jc_code varchar2(500):='';
  v_company_code varchar2(500):='';
  v_cnt number :=0;
  
  begin
  select count(*) into v_cnt from structure_enodeb_mapping where  RJ_SAPID=P_SAPID  and rownum=1;
  
  if v_cnt > 0 then 
  begin
  
   select RJ_CITY_NAME, RJ_NETWORK_ENTITY_ID,LATITUDE,LONGITUDE,RJ_STRUCTURE_TYPE,RJ_JC_NAME,RJ_JC_CODE,'6000' 
   into v_cityname,v_neid,v_latitude, v_longitude, v_structuretype,v_jc_name,v_jc_code,v_company_code from structure_enodeb_mapping where RJ_SAPID=P_SAPID  and rownum=1;

        update tbl_ipcolo_mast_info set 
        
        CITY_NAME                   = v_cityname,
        NEID                        = v_neid,
        FACILITY_LATITUDE           = v_latitude,
        FACILITY_LONGITUDE          = v_longitude,
        RJ_STRUCTURE_TYPE           = v_structuretype,
        RJ_JC_NAME                  = v_jc_name,  
        RJ_JC_CODE                  = v_jc_code,  
        COMPANY_CODE                = v_company_code
        where SAP_ID=P_SAPID;
  
  end;
  end if;   

  end UPDATE_MST_INFO_BKC;

我可以对此进行哪些调整?

jgwigjjp

jgwigjjp1#

据我所知,你的代码,它是更新TBL_IPCOLO_MAST_INFOSAP_ID = P_SAPID意味着它是更新一个记录,你必须调用每个记录的过程。
调用一次过程并一次性更新所有记录是一个很好的做法。(在您的情况下,2.5k条记录必须在此过程的一次调用中更新)
对于您的要求,目前,我已经更新了过程代码,以仅执行MERGE语句,这将与您的问题中针对单个P_SAPID的多个SQL相同。

PROCEDURE UPDATE_MST_INFO_BKC (
    P_SAPID IN   NVARCHAR2
) AS
BEGIN
    MERGE INTO TBL_IPCOLO_MAST_INFO I 
    USING (
            SELECT
                RJ_CITY_NAME,
                RJ_NETWORK_ENTITY_ID,
                LATITUDE,
                LONGITUDE,
                RJ_STRUCTURE_TYPE,
                RJ_JC_NAME,
                RJ_JC_CODE,
                '6000' AS COMPANY_CODE,
                RJ_SAPID
            FROM
                STRUCTURE_ENODEB_MAPPING
            WHERE
                RJ_SAPID = P_SAPID
                AND ROWNUM = 1
            )
    O ON ( I.SAP_ID = O.RJ_SAPID )
    WHEN MATCHED THEN 
    UPDATE SET I.CITY_NAME = O.RJ_CITY_NAME,
                I.NEID = O.RJ_NETWORK_ENTITY_ID,
                I.FACILITY_LATITUDE = O.LATITUDE,
                I.FACILITY_LONGITUDE = O.LONGITUDE,
                I.RJ_STRUCTURE_TYPE = O.RJ_STRUCTURE_TYPE,
                I.RJ_JC_NAME = O.RJ_JC_NAME,
                I.RJ_JC_CODE = O.RJ_JC_CODE,
                I.COMPANY_CODE = O.COMPANY_CODE;

END UPDATE_MST_INFO_BKC;

干杯!

j5fpnvbx

j5fpnvbx2#

3个小时?这太长了。sap_id列被索引了吗?即使没有,43 K行的数据集也太小了。
如何调用这个过程?它是另一段代码的一部分吗?也许是某个不幸的loop,它逐行执行某些操作(依次,逐行执行某些操作)?
一些反对意见:

  • 所有这些变量的数据类型都是varchar2(500)吗?考虑声明它们,以便它们采用表列的数据类型,例如v_cityname structure_enodeb_mapping.rj_city_name%type;。另外,没有必要显式地说它们的值是null(:= ''),默认情况下就是这样
  • select语句用于检查表中是否存在该参数值的内容,应重写为使用EXISTS,因为它的性能应优于您使用的rownum = 1条件。
  • 另外,考虑使用异常处理程序(如果某个ID没有行,则为no-data-found;too-many-rows(如果有两行或更多行)
  • 将数据收集到变量中的select语句具有相同的条件;您真的希望每个ID(作为参数传递)有多个行吗?

总之,整个过程的代码可以缩短为一条update语句:

update tbl_ipcolo_mst_info t set
  (t.city_name, t.neid, ...) = (select s.rj_city_name, 
                                       s.rj_network_entity_id, ...
                                from structure_enodeb_mapping s
                                where s.rj_sapid = t.sap_id
                               )
where t.sap_id = p_sapid;

如果有什么东西需要更新,它就会更新,如果没有匹配的t.sap_id,什么都不会发生。

相关问题