【実務・中級編】INDEX組み込み関数による文字列検索の最適化 – PL/Iの基本構文とデータ制御実践ガイド

PL/Iの「予約語なし」という美学と、INDEX関数による文字列検索の真実

メインフレームの現場で、若いエンジニアから「PL/Iって何でこんなに自由なんですか?」と聞かれることがある。変数を `IF` と名付けてもコンパイルが通る——。C言語やJavaに慣れた世代には、この「予約語を持たない」という仕様がカオスに見えるらしい。だが、これは設計者の英知だ。システムがどれほど巨大化しても、言語仕様の変更で既存コードが死ぬことはない。このレガシーの安定感こそ、我々がPL/Iを愛する理由の一つだ。

今日は、そんな自由度の高いPL/Iにおいて、バッチ処理の性能を左右する「文字列検索」の核心、`INDEX` 関数について深掘りしよう。

INDEX関数の「裏側」を理解する

`INDEX(string, pattern)`。ただの検索関数だと思うなかれ。この関数は、コンパイラによって最適化されると、IBMメインフレームが誇る強力な命令セットへと翻訳される。

特に、検索対象が固定長である場合や、処理系が最適化を判断できる状況下では、内部的に TRT (Translate and Test) 命令や CLC (Compare Logical Character) 命令のループ、あるいはそれらを高度に組み合わせたハードウェア命令が呼び出される。アセンブラレベルで記述されたルーチンと同等の速度が出るのは、この「組み込み関数」がハードウェアを知り尽くしているからだ。

現場での鉄則:空文字列の罠

仕様書を読み飛ばしがちな若手がよくやるミスがある。「検索対象が空文字列(”)だった場合、INDEX関数は何を返すか?」 だ。

答えは 「1」 だ。

数学的・論理的に考えれば「どこにも見つからないなら0」と期待したくなるだろう。しかし、PL/Iの仕様では、空文字列は「あらゆる文字列の先頭に存在する」と定義されている。これを理解していないと、VSAMから読み込んだ空のレコードに対して誤った条件分岐を行い、バッチが異常終了(ABEND)する原因になる。

実践的な実装例:VSAM読み込みと検索の最適化

以下のコードは、VSAMファイルからレコードを読み込み、特定の識別子を検索してフラグを立てる、バッチ処理でよくあるパターンだ。

/i
/ VSAMファイルからの読み込みと文字列検索の標準パターン /
PROC OPTIONS(MAIN);

DCL IN_REC CHAR(100) VARYING;
DCL SEARCH_KEY CHAR(10) INIT(‘ABC-DATA’);
DCL POS FIXED BIN(15);
DCL EOF BIT(1) INIT(‘0’B);

/ ファイル終了(EOF)はONユニットで制御するのがPL/I流の流儀 /
ON ENDFILE(VSAM_FILE) EOF = ‘1’B;

OPEN FILE(VSAM_FILE) INPUT;

READ FILE(VSAM_FILE) INTO(IN_REC);

DO WHILE(^EOF);
/
INDEXの戻り値を判定する際は、必ず 0 かどうかをチェックする。
もし検索対象が空文字なら 1 が返るため、ロジックが暴走しないよう注意が必要。
/
POS = INDEX(IN_REC, SEARCH_KEY);

IF POS > 0 THEN DO;
/ 検索成功時の処理:ここに複雑な業務ロジックを記述 /
PUT SKIP LIST(‘検索成功: 位置 ‘ || POS || ‘ にて発見’);
END;
ELSE DO;
/ 検索失敗時の処理 /
PUT SKIP LIST(‘対象レコードなし’);
END;

READ FILE(VSAM_FILE) INTO(IN_REC);
END;

CLOSE FILE(VSAM_FILE);
END;

パフォーマンス向上のためのチューニング・ヒント

1. VARYING属性の活用:
`INDEX` 関数は文字列の長さを内部的に参照する。`CHAR(100)` の固定長で定義すると、無駄な空白(スペース)までスキャン対象になる可能性がある。可変長文字列(`VARYING`)を適切に使うことで、実データ長のみを検索対象とさせ、CPU消費を最小化できる。

2. 組み込み関数の連鎖を避ける:
`INDEX(TRIM(A), B)` のように、引数内でさらに別の関数を呼ぶと、一時的な作業領域(テンポラリ)がスタック上に生成され、メモリ効率が悪化する。極限まで性能を絞り出したいバッチでは、事前に `TRIM` した値を別の変数に保持してから `INDEX` を呼ぶべきだ。

3. ONユニットによる例外管理:
文字列検索とは少し逸れるが、VSAM読み込み等のエラー処理は `ON ERROR` や `ON ENDFILE` を使って、メインフローから切り離すのが美しいコードの鉄則だ。エラーハンドリングを `IF` 文でネストさせると、コードの可読性が下がり、将来の保守者が泣くことになる。

最後に

PL/Iは、古い言語かもしれない。だが、ハードウェアの性能をこれほどまでに引き出せる言語は、現代の高級言語にはない魅力だ。

「予約語がない」という自由は、裏を返せば「書き手の品格がそのままコードに現れる」ということでもある。`INDEX` 関数一つとっても、その仕様を深く理解して使っているか、それとも動けばいいという感覚で使っているか。その差が、何百万行もの基幹システムの寿命を左右するんだ。

次のバッチ改修では、ぜひこの「ハードウェアに近い視点」でコードを見直してみてほしい。君の書いたコードが、次の10年、このシステムを支えることになるのだから。

タイトルとURLをコピーしました