web-dev-qa-db-ja.com

Excelスプレッドシートに基づくビッグデータの更新を処理する方法

シナリオ

  1. 選択ベースのデータは、DBからExcelスプレッドシートにエクスポートされます。
  2. いくつかの手作業はExcelファイルで行われます(不足しているデータを埋めます)。
  3. Excelファイルから変更されたデータは、DBに更新されます。

環境

  • Oracle DB
  • 元のテーブルは約700万行です
  • SQL Developerなどでインポートツールを使用できません。プレーンなSQLスクリプトである必要があります。
  • それぞれ数十万行(400〜70万)のExcelファイルがいくつかあります。

現在のソリューション

Excelファイルの各行に対して生成されたUPDATEステートメントがあります。データが変更されているかどうかをチェックします(ファイルには、古い値と新しい値の別々の列があります)。したがって、各ファイルから何十万ものUPDATEステートメントを取得します。

質問は...

この解決策はかなり単純ですが、それを行うより良い方法があるかどうか疑問に思いますか?

2
wojciech_rak

速い方法

これを行うためのおそらくより高速な方法は次のとおりです。

  1. データベーステーブルにデータを提供する
  2. このテーブルのデータをソーステーブルにマージする MERGEステートメント を実行します。

データベーステーブルのデータを提供するには、 sql loader または[外部テーブル]を使用できます。

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

次に、big_tabに次のデータがあるとします。

SQL> select * from big_tab;

    ID     VALUE1     VALUE2     VALUE3

     1         11         21         31
     2         12         22         32
     3         13         23         33
     4         14         24         34
     5         15         25         35

次の値を持つ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
)

オプション「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
;

そして得る

 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;

さらに高速な方法

変更するデータが多い場合は、さらに良い方法があります(少なくとも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;

そしてさらに速い

ロードと挿入は常にダイレクトパスmodで行う必要があります。したがって、APPENDヒントを挿入ステートメントに追加し、DIRECT=trueオプションをSQL * Loaderコマンドに追加しました。しかし、いくつかのアクションを並列化してさらに高速化することもできます。並列ステートメントはパーティションテーブルで最適に機能するため、 partition big_tabだけでなく、mod_tabおよびaux_tabも有効です。

5
miracle173

何千もの更新の代わりに、データを一時的なソーステーブルに挿入してから、ターゲットテーブルに対してマージを実行できます。

merge into target_table t
using source_table s
on (t.id = s.id)
when matched then update set t.column1 = s.column1, t.column2 = s.column2, ...;
1
sjk

明らかに、その多くの行をExcelなどのツールにエクスポートすることは、通常のアクションのように聞こえるものに対する最悪の解決策のように聞こえます。これはデータの更新です。

冒頭の投稿では、データがOracleデータベースを離れなければならない理由は見当たらない。確かにExcelのようなツールではありません。

0
tvCa