3-1.実装方針の検討~データの取得~

全体的な基本方針が固まったら、個別機能の実装設計に入ります。

バッチ処理の基本としてデータの入出力方式を考えます。
サンプルとして、同じ定義のテーブルemp_tmpからテーブルempに、社員番号が5000以上のデータを移送するのサンプルを記述しました。
簡単な仕様ですが、記述方法は主要なパターンとしても、下記の4パターンが考えられます。

サンプルコードにはOracleDBでサンプルとして提供されているemp,dept表を使用します。
また、下記のコマンドでサンプル用のテーブルを作成しておきます。
CREATE TABLE emptmp AS SELECT * FROM emp WHERE 1=0;

最もシンプルな記述は下記のようになります。

DECLARE
BEGIN
  INSERT INTO emptmp(empno, ename, hiredate, deptno)
  SELECT et.empno
        ,et.ename
        ,et.hiredate
        ,et.deptno
  FROM   emp et
  WHERE  empno >= 5000;
EXCEPTION
  WHEN OTHERS THEN
    RAISE;
END;

この記述が最もシンプルであり、高速に処理を行うことができます。

しかし、1レコードずつデータのチェックを行いたい、エラーした時点までのデータはコミットしたい、といった仕様変更があった場合にはロジックを根本から見直す必要が出てきます。

次善の策として、下記のように明示カーソルを使用し、カーソルOPEN~FETCH構文を使用することで、変更やロジックの追加が必要になった場合も、改修が容易となります。

DECLARE
  CURSOR c1 IS
  SELECT empno, ename, hiredate, deptno
  FROM   emp
  WHERE  empno >= 5000;
  r1 c1%ROWTYPE;
BEGIN
  OPEN c1;
  LOOP
    FETCH c1 INTO r1;
    EXIT WHEN c1%NOTFOUND;
    INSERT INTO emptmp(empno, ename, hiredate, deptno)
    VALUES (r1.empno, r1.ename, r1.hiredate, r1.deptno);
  END LOOP;
  CLOSE c1;
EXCEPTION
  WHEN OTHERS THEN
    IF c1%ISOPEN THEN
      CLOSE c1;
    END IF;
    RAISE;
END;

しかし、OPEN~FETCHを使用した記述は、カーソルのオープン・クローズなどの制御が煩雑になりがちですので、もう少しシンプルに記述する方法として、FORループを使用した記述が可能です。

DECLARE
  CURSOR c1 IS
  SELECT empno, ename, hiredate, deptno
  FROM   emp
  WHERE  empno >= 5000;
  r1 c1%ROWTYPE;
BEGIN
  FOR r1 IN c1
  LOOP
    INSERT INTO emptmp(empno, ename, hiredate, deptno)
    VALUES(r1.empno, r1.ename, r1.hiredate, r1.deptno);
  END LOOP;
EXCEPTION
  WHEN OTHERS THEN
    RAISE;
END;

このFOR~LOOPを使用した明示カーソルを使用した方法が最もシンプルかつ汎用的で、変更やロジックの追加が必要になった場合も、改修が容易な記述方法です。
カーソルの制御が簡略化できるのメリットです。

しかし、デメリットもあります。
Oracleの内部動作として、PL/SQLのプロセスとSQLのプロセスの間で1レコード毎に制御が移るため、性能面でのデメリットがあります。

特に、近年ではディスクの高速化により、1行ずつデータを読み込むよりも一括で読み込むことによる性能面でのメリットが大きくなってきています。

そのため、バルクコレクト、バルクインサートを使用した記述が主流となっています。

DECLARE
  CURSOR c1 IS
  SELECT empno, ename, hiredate, deptno
  FROM   emp
  WHERE  empno >= 5000;
  r1 c1%ROWTYPE;
BEGIN
  FOR r1 IN c1
  LOOP
    INSERT INTO emptmp(empno, ename, hiredate, deptno)
    VALUES(r1.empno, r1.ename, r1.hiredate, r1.deptno);
  END LOOP;
EXCEPTION
  WHEN OTHERS THEN
    RAISE;
END;

これらの各方式の長所と短所をまとめると、下記のようになります。

システムの内容や状況に応じて、実装方式を選択しましょう。

2018-01-26

Posted by tfurukaw