メニューボタン
IBMi海外記事2012.09.19

Open Access for RPG (RPG OA)によるプログラムのパフォーマンスの向上

ダン・クルックシャンク 著

RPG IVプログラムにおけるデータ・アクセス操作のパフォーマンスを劇的に改善

1回のシーケンシャルな読み出し操作の後にランダムな読み出し操作を1回以上使って複数のファイルからデータを取り出すプロセスは、プログラム・ジョインと呼ばれています。従来の入出力方法によって返された値をテストすることは、データのプログラム選択と呼ばれています。こうしたテクニックを過度に使用するプログラムは、CPUの過剰使用とディスク入出力の過剰操作の主要な犯人としてパフォーマンス・エクスプローラ(PEX: Performance Explorer)ヒット・リストの上位40位に常に入ってきます。

さらに驚かされるのは、ファイルのプログラム・ジョインは、今ではDB2 for iとして知られている統合リレーショナルデータベースにデータを定義したりデータにアクセスしたりする方法の代わりにIBMがOS/400にSQLを組み入れた20年以上前に時代遅れになったということです。しかしIT部門の多くではSQLを使用しませんでしたし、SQLを「禁止」する部門さえありました。図1に示した通り、従来のアプリケーションと比べて適切に調節されたSQLアプリケーションを使用することで得られる大幅なパフォーマンス向上を考えると、SQLの使用に抵抗することは理解に苦しみます。

図1: 従来の入出力を使用して呼び出されたRPGプログラムに示したデータは従来の入出力(SETLL、READE、CHAIN)を使って4回呼び出されていろいろな結果セットを返したRPGプログラムを表しています。合計で128回の論理(メモリ)入出力操作が実行されました。SQLハンドラを使用するように同じプログラムを修正したものは合計で4回のブロックFETCH操作を実行しています。図1のグラフからおわかりの通り、この修正により論理入出力が劇的に減少しています。

従来の入出力を使用して大量のデータ・セットを処理する非効率的なアプリケーションを保守する仕事に縛られている開発者にも望みはあります。IBM Rational Open Access: RPG EditionでRPG IVにHANDLERキーワードが追加されたことで、複数の入出力操作をさえぎってSQLの高度な機能を使用したより効率的でモダンな方法に変換する手段が提供されました。ここでは、このOpen Access for RPGまたはRPG OAと呼ばれるRPG IV拡張を使用してRPGプログラムにおけるデータ・アクセスのパフォーマンスを改善する方法について説明します。

なぜデータ・アクセスをモダン化するのか

図1に示す劇的なパフォーマンスの向上には簡単な理由があります。それはブロッキングです。このテストには128回の入出力操作が含まれています。たとえばこの操作の回数が1200万回(多くの中小企業では典型的な回数です)あるいは1億2800万回(IBM iを使用している企業では典型的な回数です)だったと想像してみてください。もっとも効率的なデータ・アクセス方法を採用しないことで、従来の入出力操作を使用して大規模なデータ・セットを処理し続けている多くの企業ではIT予算をソフトウェア(人件費、研修、ツール)ではなくハードウェア(メモリ、CPU、ディスク)により多く費やさざるを得ませんでした。

多くの開発者はモダンなテクニックと新しいツールを切望しています。しかし残念なことに数十年前に開発されたレガシーなコードにとらわれているのかもしれません。こうしたプログラムには(何千とまでは言わないまでも)何百行というコードが書かれています。こうした巨大な悪夢のコードの中のたった1行のコードでも変更することを考えると、熟練したソフトウェア・エンジニアリングの第一人者でさえも動揺します。しかしそれも今日までの話です。

2回のシリーズからなる本稿では、データ・アクセスをモダン化して、複数のテーブルをジョインするSQLビューに対してSQLのブロックFETCHを使用するのではなく、ランダム入出力操作(つまりSETLL、READE、CHAIN)を組み合わせて複数のファイルに対して使用するRPGプログラムを変換する(CHAINGANGR、別名Working On the Chain Gang)というIBMの戦略に従います。ここでは1台の緑色画面の助けを借りずにモダン開発ツールを使用してこれを実現します。詳細についてはこちらにあるIBMデータ・アクセスのモダン化戦略をご覧ください。

CHAINGANGRアプリケーションでのデータ・アクセスをモダン化する手順は以下の通りです。

  1. テスト用データベースを作成
  2. SQLビューを作成
  3. SQLビューにアクセスするSQLを使用するハンドラ・プログラムを作成
  4. このハンドラを使用するように既存のILE RPGプログラムを修正

本稿ではこのうちの最初の2つの手順について説明し、パート2では手順3と4について説明します。上記の手順を完成させるには以下の項目が必要となります。

  1. IBM i systemのバージョン6.1またはそれ以降のバージョン。このシステムには最新のPTF、HIPER PTF、DB PTF (SF99601)がインストールされていることが理想です。
  2. IBM Rational Developer for Power Systems Software (RD Power) 8.0およびIBM Rational Application Developer (RAD) 8.0 (別名Power Tools for i)またはIBM Rational Business Developer (RBD) 8.0 (別名RDi for SOA Construction)。これらのバンドル製品にはRPG/COBOL Development ToolとData Project Explorer for SQL developmentが含まれています。すでにRDiをお持ちの場合は、開発の必要性に応じてRAD、RBDまたはその両方を追加することができます。
  3. 性能の高いPC -- お子さんのPCを拝借できるかどうか頼んでみてください。

さて、なぜこれらの開発者用「パワー・ツール」が必要なのでしょうか。フローチャート・テンプレートあるいはプレゼンテーション・ツールを使用することでアイデアを紙に描きやすくなりますが、こうしたツールは実際のコードや関連する成果物を開発する段になると不十分です。パワー・ツールへの投資が効果を上げるのはまさにこうした場面です。

テスト用データベースの作成

開発プロセスを開始するにはデータベースが必要となります。しかし心配はありません。いずれのIBM iにも独自の「組み立て式おもちゃ」であるデータベースを作成してテストするためのユーティリティが付いています。このツールはQSYSにあります。データベースを作成するにはRational Data Source Explorerを使用してDB2 for iへ接続するところから始めます。(このユーティリティを初めてお使いになるのであれば、[New Connection Profile]ウィザードを使用してIBM i 6.1あるいは7.1システムに接続してください。)

接続が完了したらスキーマ、QSYS、ストアード・プロシージャを開きます。(スキーマのリストは[Schemas]を右クリックしてポップアップ・メニューから[Filter]を選択してフィルタをかけます。) ストアード・プロシージャのリストから[CREATE_SQL_SAMPLE]を右クリックし、ポップアップ・メニューから[Run]を選択します。これにより[Specify Parameter Values]ウィンドウが表示されます。図2:Rational Data Source Explorerからストアード・プロシージャを実行に示した通り、スキーマ名(ここではDB2SANDBOXを使用しました)を入力してDB2 Sampleスキーマを作成します。

Data Source Explorerビューに戻ってスキーマのリストをリフレッシュすることで、新しいサンドボックス・スキーマが作成されたことを検証することができます。リストをフィルタにかけるには、[Schemas]を右クリックして[Disable Filter]のチェック・ボックスを外します。図3:新しいスキーマの検証に示した通り、[Expression]ラジオ・ボタンを選択してスキーマ・リストに追加したいスキーマを選択します。注: [Meet any condition]ラジオ・ボタンを必ず選択してください。そうでないとスキーマ・リストが空っぽになってしまいます。

SQLビューの作成

次のステップはRPGハンドラ・プログラムがアクセスするSQLビューを作成することです。これには以下のタスクが含まれます。

  1. アクセスするテーブルを識別
  2. 結果セットをマップ
  3. JOIN基準を確立
  4. 「プログラム選択」を押し下げ
  5. ビューを最適化

アクセスするテーブルを識別する最も簡単な方法は、修正対象のRPGプログラムに対してIBM i OS Display Program Reference (DSPPGMREF)コマンドを実行することです。出力を一時ファイルに送信し、次にそのファイルをIBM iのクロス参照ファイルにジョインします。これを実行するSQLのストアード・プロシージャの例を図4に示します。

図5のテーブルには、図4のストアード・プロシージャに入力パラメータ「DB2SANDBOX」と「CHAINGANGR」を与えて実行して得られた結果セットが含まれています。

SQLストアード・プロシージャを書くのが初めてであれば、[New Stored Procedure]ウィザードを使ってみることを考えてください。このウィザードは[Data Projects Explorer]ビューからアクセスできます。このウィザードはRDB、RAD、IBM InfoSphere Data Architect (IDA)で提供されています。

アクセスするテーブルが識別できたら、次のステップはSQLの結果セットの列を、RPGプログラムで使用されているDDSファイルに基づくRPGの入力バッファにマップすることです。場合によっては、SQLテーブルは新しいデータ・タイプ、NULL値、およびRPG言語風に変換しなければならないその他のSQL機能を利用しているかもしれません。SQLプログラミングの初心者であるRPGプログラマの多くはこうした細かなニュアンスに悩まされ面倒だと思うでしょう。イライラするのはCVTOPTコントロール・キーワードを追加するのを忘れるか、null値を処理するインジケータ配列を定義しなかったときです。

このイライラは、データをRPGプログラムが使用する前にSQLビューを使用してデータを変換し、NULL値を除去することで解消することができます。これを行うのにはSQL関数CHARとCOALESCEを利用することができます。SQLのCHAR関数はVARCHAR、DATE、TIMEフィールドをDDSファイルのフィールド定義にマッチするように変換するのに使用することができます。COALESCE関数はNULL値をゼロ、空白、または特定の値と交換するのに使用することができます。

もう一つ重要なタスクは実際に使用されている列を識別することです。レガシー・プログラムのほとんどは、物理ファイルのフォーマットを共有しているDDS論理ファイルを使用しています。こうするとほとんどの列が使用されないことになるかもしれません。しかし、データをメモリからプログラムのバッファに移動するときはこの列を考慮に入れなければなりません。こうした参照されないフィールドがSQLのビューに含まれないようにすることが重要です。

図6に示すテーブルにはプログラム中で実際に使用されているDDSフィールドからSQL列へのマッピングと、SQLビューで使用されている抽出された列が含まれています。

このテーブルにある情報は、いくつかのVARCHAR列がDDSの定義に対応するようにCHARに変換されていることを示しています。さらに、DATEタイプ列はRPGプログラムが望んでいる値にマッチするように変換されています。最後に、COALESCE関数を使用してDEPTNAME列に非NULL値が入るようにしています。

CREATE VIEW文のSELECT部分の例を図7に示します。最後の列名は大文字になっています。データ変換SQL関数で使用されている列の名前を与えることで、別の列リストになることを回避することができます。

次に、SQLビューで使用されるJOIN基準を確立します。これにはRPGプログラムを分析してファイルがどのようにアクセスされるのかを調べる必要があります。私たちが探しているのは入れ子になったループの開始点です。この開始点は通常SET操作を使って、主要ファイルを1つ以上のキー値によって決められた開始点に位置付けをすることによって識別されます。主要ファイルは次にファイルの終わり(イコール・キーの終わり)に到達するまでREADE操作またはREAD操作によって処理されます。ループ内では1つ以上の追加のファイルがCHAIN操作によってランダムにアクセスされます。図8にはCHAINGANGRプログラム中のRPGの入れ子になったループとそれに対応するSQLのジョイン構文とを比較したものを示してあります。

ジョインのタイプ(たとえばINNER、OUTER、EXCEPTION等)はCHAIN操作の結果によって決まります。たとえば、列が見つからずにIF文のELSE節にITERが含まれている場合は、INNERジョイン(つまりREADによって処理された列はスキップされる)になります。ELSE節に列が見つからない条件のデフォルト値を提供するコードがある場合はLEFT OUTERジョインと等価になります。マッチしない2次テーブルからの列用のNULLをSQLが返すという点が重要です。COALESCE関数を使用してこの場合のデフォルト値を返すことができます。

入れ子になったループの分析中は、IF %FOUND節(別名データのプログラム選択)の一部として実行される追加のIFテストを調べてください。たとえば、EMPNAMEファイルに対してCHAIN操作がうまくいったあとにEMP_STATUSフィールドが「A」となっているかどうかを調べるテストが行われます。もし「A」になっていない場合はITERが実行され、EMPPRJACT行がバイパスされます。条件が真となる場合、このビジネス・ルールをSQLビュー内のEMPNAME用にJOINのON節に押し下げます。SQLジョインの実行結果はジョインと選択テストの両方を満たすすべての行になります。RPGプログラム・ロジックを変更する必要はありません。それはすべてのプログラム・データ選択テストが多数の少ない行数のテストで真となるからです。データ・アクセスのビジネス・ルールをSQLビューに押し下げている例を図9に示します。

JOIN基準の付いたCREATE VIEW文の例を図10に示します。ON節はジョイン列を定義しCHAIN操作と等価になります。

これでSQLビューを構築する準備ができました。ここでRational Integrated Development Environment (IDE)を使用してSQL CREATE VIEWスクリプトを記述して配布します。準備ができたらIBM iに接続するだけです。接続できたら図11に示すようにSQLスクリプトを右クリックしてポップアップ・メニューから[Run SQL]オプションを選択します。[SQL Results]ウィンドウをチェックしてSQLビュー・オブジェクトが正しく作成されていることを確かめることができます。

この時点で、ビューを最適化する準備が整いました。ビューを最適化するにはビューに対して異なる選択および順序付け基準を使用してSQL SELECT文を実行するだけです。そうです、ビューをテストするプログラムを書く必要はありません。

最初のステップは、RPGの入れ子になったループの主要ファイルがアクセスするDDS論理ファイルで使用されているキー(今回の場合EMPPRJACT)の数を調べることです。次にキーの使用方法(つまり選択、ジョイン、順序付け)を調べます。これはRPG SETLL操作によって使用されるキーをチェックすることで行えます。この目的は適切なSQL WHERE節とORDER BY節を作成することです。

図12に示すテーブルにはRPGプログラム内のキーの使用方法に基づいたSQLビューをテストするのに使用するSQL文の例が含まれています。

図12に示すSELECT *の使用方法は通常、ベース・テーブルや物理ファイルにアクセスする方法としては良い方法ではありません。しかし、必要とする列にアクセスするだけのビューを労苦を惜しまずに構築してきたのですから、SQLビューに対してSELECT *を使用することは全く問題ありません。WHERE節はRPG SETLL操作で使用されているキーに基づいています。ビューの外でWHERE節をコーディングすることでビューの再利用性を高めてプログラムの保守の手間を削減することができます。ORDER BY節にはDDSキー付きの論理ファイルからのキー・フィールドがすべて含まれています。SQLビューにはORDER BY節を含めることができませんので、ビューの外側でコーディングします。またこれにより再利用性と動的な順序付け機能が可能になります。

SQLとRPG(およびその他のHLL)の大きな違いは、インデックス(キー付きの論理ファイル)がジョイン列に存在していなくてもSQLを実行できるということです。別の言い方をすると、キー付きの読み込みを実行するRPGプログラムはキー付きの論理ファイルを必要とします。キー付きの論理ファイルがないと実行はおろかコンパイルさえできません。一方SQL文はインデックスがなくても実行できます(実行性能が悪いことは付け加えておきます)。

ジョインのパフォーマンスを最高に保つには、最低限でもジョインに使用される各列に対して二進化基数インデックスが存在していることを確かめてください。上手に設計されたデータベースにはアプリケーションのコードを記述する前にすでにこのインデックスがあります。このインデックスは制約(プライマリおよび外部キー)と呼ばれ、二つのテーブルの間の自動ジョイン・パスを提供しています。

性能を最適化するためには、ローカルの選択列(別名選択/省略フィールド)とジョイン列を結合するインデックスを作成します。ジョイン列の前にequal選択列のインデックスと、ジョイン列の後にequal選択列のインデックスという2つのインデックスを作成することを検討してください。

さらに、インデックス・オンリー・アクセスを利用するSQLの自動機能を利用することも検討してください。言い換えると、結果セットに必要なすべての列がそのインデックスから取得できるのであれば、物理ファイルにアクセスする必要はありません。物理ファイルへのアクセス(別名、テーブル探索)が必要でなくなることは、バッチのランタイムの削減と対話によるスループットの増大という意味で大きな違いとなります。

SQLビューのテスト結果とSQL文を処理するのに使用するVisual Explainアクセス・プランを図13に示します。CHAIN操作がされたファイルに対するインデックス・オンリー・アクセスを使用している点に注意してください。

次のステップ: ハンドラの作成と使用

本稿が長くなり過ぎないようにここで説明を一旦区切り、続きはパート2で説明したいと思います。次の記事ではRPGハンドラを作成してSQLビューにアクセスする処理を説明します。そこではデータ構造を使用して情報をRPGプログラムからハンドラやSQLブロックFETCHルーチンに渡し、既存のILE RPGプログラムを修正してハンドラを使用する方法について触れます。ではまた次回お逢いしましょう。

あわせて読みたい記事

PAGE TOP