DBエンジンを最大限に生かすバッチアプリの作り方Oracle技術者のためのバッチアプリ開発講座(2)(2/3 ページ)

» 2008年09月30日 00時00分 公開
[白砂丈太郎株式会社ワン・オー・ワン]

カーソルもfor文も使わない条件分岐処理を会得せよ

 カーソルを使用したループ処理を行わずにリスト1のような条件分岐を行うには、どうしたらよいでしょうか?

結果セットに対して一気にSQLで処理を実行する

 大量データを扱うバッチ処理を実装する際には、「データを1件ずつ条件分岐させて処理する」というプログラミング的な発想ではなく、「同一条件のデータを1つの結果セットとして取り出して一括処理する」という視点が必要になります(図2)。

図2 結果セットの一括処理 図2 結果セットの一括処理

  前ページリスト1のカーソルを使用したループ処理は、リスト2のようなSQLに置き換えることができます。

--key列が5以下のレコードは、value列を10倍にして一時テーブルに挿入する
INSERT INTO t1_temp
SELECT      key,
            value * 10
FROM        t1
WHERE       key <= 5;
--key列が5より大きいレコードは、value列を20倍にして一時テーブルに挿入する
INSERT INTO t1_temp
SELECT      key,
            value * 20
FROM        t1
WHERE       key > 5;
--処理を確定する
COMMIT;
リスト2 結果セットの一括処理

 リスト2のSQLでは、次のような処理を行います。

  1. key列が5以下のレコード群をテーブルt1から抽出し、value列を10倍して一時テーブルt1_tempに挿入する
  2. key列が5より大きいレコード群をテーブルt1から抽出し、value列を20倍して一時テーブルt1_tempに挿入する

 このようにSQLのみで処理を記述すれば、リスト1のような実行エンジンの切り替えが発生しません。Oracleなどのデータベース管理システムでは、結果セットに対する処理を非常に得意としています。大量データを処理するロングトランザクションでは、同一条件のデータを1つの結果セットとして取り出して一括処理することで、処理性能を飛躍的に向上させることができます。

CASE式の使いどころを理解しよう

 リスト2のSQLは、CASE式を使用してリスト3のように記述することもできます。

--key列が5以下のレコードは、value列を10倍にして一時テーブルに挿入する
--key列が5より大きいレコードは、value列を20倍にして一時テーブルに挿入する
INSERT INTO t1_temp
SELECT      key,
            CASE
              WHEN key <= 5 THEN value * 10
              ELSE value * 20
            END
FROM        t1;
--処理を確定する
COMMIT;
リスト3 CASE式を使用した処理

 CASE式はSQL-92で標準に取り入れられた機能で、SQL内に条件分岐処理を記述する際に使用します。非常に便利な機能の割に、その真価はあまり知られていないかもしれません。CASE式を有効活用することにより、これまでPL/SQLで実装しなければならなかったような複雑な処理をSQLのみで実装することができます。

 リスト2ではSQLを2回発行しているのに対し、CASE式を使用したリスト3の場合は1回のSQLで処理を行っています。つまり、リスト2では同じ抽出元テーブルを2回スキャンする必要があるのに対し、CASE式を使用したリスト3の場合は1回のスキャンで済むことになります。また、発行するSQLの数が減るということは、事前に解析する必要のあるSQLの数が減るということです。このように、できるだけ少ないSQLで処理を実装すれば、性能上大きなメリットを得ることができます。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。