如何处理基于excel电子表格的大数据更新

woj*_*rak 2 oracle oracle-11g-r2 excel update

设想

  1. 基于选择的数据从 DB 导出到 Excel 电子表格。
  2. 对 excel 文件进行了一些手动工作(填充缺失数据)。
  3. 来自 excel 文件的更改数据更新回 DB。

环境

  • 甲骨文数据库
  • 原始表大约有 700 万行
  • 不能在 SQL Developer 等中使用导入工具,必须是纯 SQL 脚本。
  • 有几个 excel 文件,每个文件有几十万行(400-70 万)

当前解决方案

UPDATE为excel文件的每一行生成一个语句。它检查数据是否已更改(文件具有用于旧值和新值的单独列)。因此,从每个文件中我们得到了数十万条UPDATE语句。

问题是...

这个解决方案相当简单,但我想知道是否有更好的方法来做到这一点?

mir*_*173 6

快速方法

一种可能更快的方法是:

  1. 提供数据库表中的数据
  2. 执行MERGE 语句,将该表中的数据合并到源表中

要在数据库表中提供数据,您可以使用sql loader或 [external tables]。

http://docs.oracle.com/database/121/SQLRF/statements_9016.htm#SQLRF01606

create table big_tab(
  id number primary key,
  value1 number,
  value2 number,
  value3 number)
;

create table mod_tab(
  id number,
  value1 number,
  value2 number,
  value3 number)
;
Run Code Online (Sandbox Code Playgroud)

现在假设您在 big_tab 中有以下数据。

SQL> select * from big_tab;

    ID     VALUE1     VALUE2     VALUE3
Run Code Online (Sandbox Code Playgroud)
     1         11         21         31
     2         12         22         32
     3         13         23         33
     4         14         24         34
     5         15         25         35
Run Code Online (Sandbox Code Playgroud)

你有一个带有以下值的 csv 文件 mod_data.csv

1,111,121,131
3,113,123,133

您可以使用sqlldr load.ctl DIRECT=true包含 sql 加载器控制文件 sql.ldr 将其加载到表中

LOAD DATA
INFILE "mod_data.csv"
TRUNCATE
INTO TABLE mod_tab
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
TRAILING NULLCOLS
(
  id char,
  value1 char,
  value2 char,
  value3 char
)
Run Code Online (Sandbox Code Playgroud)

使用选项“DIRECT=true”会比没有这个选项的加载速度更快。现在你有

SQL> select * from mod_tab;

        ID VALUE1 VALUE2 VALUE3
---------- ---------- ---------- ----------
         1 111 121 131
         3 113 123 133

您可以使用以下语句将其合并到 big_tab 中

MERGE INTO big_tab 
using mod_tab on (big_tab.id=mod_tab.id)
when matched then update
  set 
    value1=mod_tab.value1,
    value2=mod_tab.value2,
    value3=mod_tab.value3
;
Run Code Online (Sandbox Code Playgroud)

并得到

SQL> select * from big_tab;

        ID VALUE1 VALUE2 VALUE3
---------- ---------- ---------- ----------
         1 111 121 131
         2 12 22 32
         3 113 123 133
         4 14 24 34
         5 15 25 35

如果处理没问题,你可以清理

    truncate table mod_tab;
Run Code Online (Sandbox Code Playgroud)

更快的方法

如果你有很多数据要修改,有一种方法会更好(至少如果你的 io 系统很快):

  1. 创建与 big_tab 表结构相同的辅助表
  2. 在此辅助表中插入修改行
  3. 将 big_table 中不会被修改的行插入到辅助表中
  4. 删除 big_tab 表
  5. 将辅助表重命名为 big_tab。
  6. 向新的 big_tab 表添加约束和索引

这可以通过以下脚本完成

create table aux_tab as select * from big_tab where 1=0;
alter table mod_tab add  primary key (id);
insert /*+ APPEND */ into aux_tab select  big_tab.id id,
    decode(mod_tab.id,null,big_tab.value1,mod_tab.value1) value1,
    decode(mod_tab.id,null,big_tab.value2,mod_tab.value2) value1,
    decode(mod_tab.id,null,big_tab.value3,mod_tab.value3) value3
  from big_tab, mod_tab
  where big_tab.id=mod_tab.id(+)
;
drop table big_tab;
rename aux_tab to big_tab;
alter table big_tab add  primary key (id);
alter table mod_tab drop  primary key;
truncate table mod_tab;
Run Code Online (Sandbox Code Playgroud)

甚至更快

您应该始终加载并插入直接路径模块。因此,我添加并APPEND提示了插入语句和DIRECT=trueSQL*Loader 命令的选项。但是你可以尝试并行化一些动作来获得更快的速度。并行语句在分区表上工作最佳,因此对big_tab 以及 mod_tab 和 aux_tab进行分区可能是有意义的。