字段名称存储在表中时如何改进数据加载

Posted

技术标签:

【中文标题】字段名称存储在表中时如何改进数据加载【英文标题】:How to Improve data loading when field name is stored in a table 【发布时间】:2014-03-16 01:04:32 【问题描述】:

我需要使以下代码高效(加速)。它非常慢。 我正在更新并插入到多个表中,要更新的字段名称存储在一个临时表中,布局如下:

变量名 变量名的值 foreign_key1 foreign_key2 数据库表名

代码:

DECLARE

  TYPE t_char_array IS TABLE OF VARCHAR2(32) INDEX BY BINARY_INTEGER;
  t_cursor SYS_REFCURSOR;
  t_id t_char_array;
  t_varnm t_char_array;
  t_valuex t_char_array;
  t_fpk1 t_num_array;
  t_dbtable t_char_array;
  t_fpk2 t_num_array;
  t_row_count NUMBER :=0;
  sql_stmt VARCHAR2(700);
  sql_cursor VARCHAR2(300);
  sql_inserr VARCHAR2(100);

   BEGIN
      sql_cursor :='SELECT id, varnm, valuex,fpk1,dbtable, fpk2 FROM '||&tableq;

     OPEN t_cursor for sql_cursor;
        LOOP
           FETCH t_cursor
               BULK COLLECT INTO t_id, t_varnm, t_valuex, t_fpk1, t_dbtable,t_fpk2

     LIMIT 1000;
     EXIT WHEN t_row_count = t_cursor%ROWCOUNT;
     t_row_count := t_cursor%ROWCOUNT;

     FOR i IN 1..t_id.count loop
         if t_dbtable(i) =' Temp_table' then
            sql_stmt:='UPDATE Temp_table SET '||t_varnm(i)||' =:1
                  WHERE pk = '||t_fpk1(i)||' and dictionary_pk = '||t_fpk2(i) ;

            if t_vartype(i) ='D' then 
                 EXECUTE IMMEDIATE sql_stmt using to_date(t_valuex(i),'YYYYMMDD');
            else
                 EXECUTE IMMEDIATE sql_stmt using (t_valuex(i));
            end if; 

            if sql%rowcount = 0 then
                 sql_stmt:='insert into Temp_table (pk, fpk2,'||t_varnm(i)||' )
                         VALUES (seq_steps.nextval,t_fpk2(i),t_valuex(i))';
            end if;          

        end if;
     end loop;
         exit when t_id.count < 1000; 
  end loop;
commit;

【问题讨论】:

【参考方案1】:

将多个 INSERT 和 UPDATE 组合成较少数量的 MERGE。这种方法将从输入表中读取更多次,但可能会显着减少动态 SQL 的数量。这实际上是更多合乎逻辑的工作,但它可能会执行得更好,因为它减少了 SQL 和 PL/SQL 之间的切换。

begin
    for merges in
    (
        select distinct id, varnm, vartype
        from &tableq
        where dbtable = ' Temp_table'
    ) loop
        execute immediate '
            merge into temp_table
            using
            (
                select fpk1, fpk2,
                    '||case when mergest.vartype = 'D' then
                        'to_date(valuex, ''YYYYMMDD'')'
                    else 'valuex' end||'
                from &tableq
                where varnm = :merges_varnm
                    and vartype = :merges_vartype
            ) new_data
            on
            (
                temp_table.pk = new_data.fpk1
                and
                temp_table.dictionary_pk = new_data.fpk2
            )
            when matched then update set
                '||merges.varnm||' = new_data.valuex
            when not matched then insert(pk, fpk2, '||merges.varnm||')
                values(seq_steps.nextval, new_data.fpk2, valuex)
        ' using merges.varnm, merges.vartype;
    end loop;
end;
/

【讨论】:

感谢您的导入。我尝试了这种方法,它的性能比上面的差一点。同样令人困惑的是,我仅使用 11k 条记录对此进行了测试,但加载数据需要 46 分钟以上。有没有办法在我的情况下使用 forall?

以上是关于字段名称存储在表中时如何改进数据加载的主要内容,如果未能解决你的问题,请参考以下文章

如何更改 DataFrame 的架构(修复一些嵌套字段的名称)?

将存储在表字段(没有引用表)中的选项值转换为相应的文本

页面重新加载后如何保持在反应(antd)表中的同一页面

将数据加载到 SQL 表中时处理特殊字符和转义字符

jqGrid如何做字段在表全部数据中唯一性函数校验

SQLSERVER如何在数据库里根据某个字段,查出该表名字