オブジェクトの使用状況の統計データ
昔々、はるか彼方のシステムで、IBMは、システム上のすべてのオブジェクトの「オブジェクト記述(Object Description)」に「 最終使用日(Date Last Used) 」を追加しました。「最終使用(last used)」というのは、オブジェクト タイプによって、それぞれ異なることを意味します。たとえば、*FILEオブジェクトの場合は、最後にファイルがオープンされた、または最後にその記述が変更された、という意味になります。*PGMオブジェクトの場合は、最後にプログラムが呼び出された、という意味です。その他のオブジェクトの場合は、最後に表示、検索/読み取り、更新されたなど、それぞれ異なる意味になります。唯一の例外は、「装置記述(Device Descriptions)」です。これは、*DEVDが「オンへの構成変更保留中(Vary On Pending)」から他のステータスへ変更されると更新されます。
「最終使用日」は、1日に1回更新されるのみです。ある日にそのファイルが百万回オープンされたとして、「最終使用日」が「今日の」日付に設定されるのは、その日の最初の オープン 時だけです。「最終使用日」の値は、8バイトのシステム タイムスタンプ(日付および時刻コンポーネント)として格納されますが、有効なのはそのタイムスタンプの日付部分のみで、時刻部分は破棄されます。
では、「PGMA」という架空のプログラムについて見てみましょう。
作成日: 1988年06月21日
最終使用日: 2023年06月07日
「PGMA」という*PGMオブジェクトは、35年前に作成され、最後に使用されたのは今年の6月7日でした。つまり、このオブジェクトは、つい最近、本記事執筆のほんの数週間前に使用されたということです。それでは、このオブジェクトは定期的に利用されていると言うことはできるでしょうか。たとえば、オブジェクトが作成されてから12,000日をはるかに超える期間で、呼び出されたのが1回だけだったとしたらどうでしょうか。あるいは、6月7日に開発者がPGMAのデバッグを始め、stmt 1のブレークポイントで呼び出して、どのような処理を行っているか確認してからプログラムを終了していたとしたらどうでしょうか。確かに「最終使用日」は更新されますが、その日付からは、あまり多くの情報を読み取ることはできません。
場合によっては、「最終使用日」は更新されても、オブジェクトが本番環境で更新されたことを意味するわけではないというケースも考えられるということです。「最終使用日」は有用なプロパティですが、それだけで、すべてが分かるわけではありません。
使用日数カウント(Days Used Count)
オブジェクトの使用状況に関連のあるもうひとつの属性として、「使用日数カウント(Days Used Count)」があります。これは、「最終使用日」が更新されると値が増加する整数値です。そのため、上述の通り、値が増加するのは1日1回だけです。このカウンターによって、話の流れがつながります。もう一度、架空の「PGMA」のオブジェクト記述を見てみましょう。この「使用日数カウント」を含めると、以下のようになります。
作成日: 1988年06月21日
最終使用日: 2023年06月07日
使用日数カウント: 2日
これを見ると、PGMAは、過去35年間で合計2回呼び出されたことがあることが分かります。35年間で2回使用されたプログラムというのは、必ずしもその組織が実際に使用しているものというわけではなさそうです。しかし、これもまた、すべてを物語るわけではありません。
使用日数カウントのリセット日(Days Used Count Reset Date)
「使用日数カウント」には、対になる「使用日数カウントのリセット日(Days Used Count Reset Date)」というプロパティがあります。
これは、ブランク/nullであることが多いのですが、特定の日付が設定されていることもあります。この値は、CHGOBJD(オブジェクト記述変更)コマンドのUSECOUNT(使用日数カウント)パラメーターによって設定されます。USECOUNT(*RESET)が指定されている場合、この「使用日数カウントのリセット日」はそのジョブの日付に設定され、「使用日数カウント」は0に設定されます。
「使用日数カウント」は、以下に示す日以降で、プログラムが呼び出された(またはファイルがオープンされた)日数ということになります。
- 「使用日数カウントのリセット日」がブランク/nullでない場合:
「使用日数カウントのリセット日」の日。 - 「使用日数カウントのリセット日」がブランク/nullの場合:
オブジェクトが作成された日。
ハウスキーピング処理
Cozzi Research社で提供している、「SQL Tools」オファリングには、SQL関数が数多く含まれていますが、あるクライアントから、使用されていないオブジェクトや、使用頻度の少ないオブジェクトのリストを抽出したいという要望がありました。また、彼らは、オブジェクトが利用可能となっていた日数についても知りたかったようです。それが分かると、利用可能なオブジェクトに対する、使用されているオブジェクトの割合を計算できるようになるためです。たとえば、あるオブジェクトが35年前に作成され、使用されたのは2回という場合、そのオブジェクトはおそらく削除しても良さそうです。しかし、オブジェクトが35日前に作成されて、2回使用されている場合は、おそらく残しておいたほうが良いでしょう。
こうした問題を解決するために、私が提唱する「Thinking in SQL™(SQLで考える)」手法を応用して、問題解決に当たりました。まずは、クライアントが知りたい情報を提供する、結果として生成される値を定義しました。
- オブジェクト名(Object name)、オブジェクト タイプ(Object type)、オブジェクト サイズ(Object size)、オブジェクトの所有者(Object owner)、オブジェクト記述(Object description)など。
- 作成日(Creation Date)
- オブジェクト作成後の経過時間(日数)(Object Ages)
- 最終使用日(Last Used Date)
- 使用日数カウント(日数)(Days Used Count)
- 使用日数カウントのリセット日(Days Used Count Reset Date)
- オブジェクトが利用可能となっていた日数(Days Object has been available to be used)
- オブジェクトが使用された日数のパーセンテージ(Percentage of days when the object was used)
ここでは、共通表式(CTE)を使用して列を作成し、計算を行ってから、SELECTステートメントを使用してそのデータにアクセスするだけです。これは、派生フィールドが含まれるときにSQLソリューションを記述するための最も明確な方法だと思います。
ここで使用しているCTE名はOBJUSAGEです。この例では、そのCTEで生成される、それぞれの結果列(フィールド)にも明示的に名前を指定しています。列名の指定は任意ですが、resultSet列の命名を単純化できるケースもあります。たとえば、OBJLONGSCHEMAは別の形へキャストされ、日付のキャストも、経過日数の計算も、すべて列名を指定したことが役に立っています。
WITH objUsage (objlib, objname, objtype, objattr, lastUsedDate, crtdate, objAge,
usageResetDate, days_used_counter, days_Available, usage_Percentage,
objowner, objcreator, objsize, objtext) AS (
SELECT cast(left(objLongSchema,10) as varchar(10)),
objname,
objtype,
objattribute,
CAST(last_used_timestamp AS DATE) AS LastUsedDate,
CAST(objcreated AS DATE) AS CrtDate,
DAYS(current_date) - DAYS(objcreated) AS ObjAge,
CAST(last_Reset_Timestamp AS DATE) AS UsageResetDate,
days_used_count AS Days_Used,
DAYS(current_date) -
DAYS(COALESCE(last_Reset_timeStamp, objcreated)) + 1
Days_Available,
CAST(
100.00 *
(Dec(days_used_count, 7, 2) /
dec( 1 + DAYS(current_date) -
DAYS(COALESCE(last_Reset_timeStamp, objcreated)), 7, 2))
AS DEC(5, 2)) Usage_Percentage,
objowner,
objDefiner,
objsize,
objtext
-- Change the two parameters to '*ALLUSR' and '*ALL'
-- to scan your entire system, otherwise change the
-- Library and object type parameters as desired.
FROM TABLE(object_statistics('PRODLIB', '*PGM *SRVPGM')) OL
)
SELECT *
FROM objUsage
-- To speed up your initial results, omit the ORDER BY clause entirely
ORDER BY Usage_Percentage DESC,
days_used_counter DESC,
objlib,
objname
私はいつも、IBMのOBJECT_STATISTICSではなく、「SQL Tools」のOBJECT_LISTを使用するようにしています。これは、IBM i V7R2以降では、同じ結果を返すためです。しかし、この例でのOBJLONGSCHEMAのCASTは、V7R2以降で十分に機能するようです。
このコードは、直接カット&ペーストするか、または、私のGITHUBページ(こちらのリンク: https://github.com/bobcozzi/OBJUSAGE)からダウンロードして使用することができます。
このコードをIBM ACSの「SQLスクリプトの実行」に直接カット&ペーストするか、または、ソース ファイル メンバーに保存して、SQL iQueryを使用してコマンド入力画面を介して実行します。以下は、私のテスト区画の1つからの出力例です。
![](/images/ITj2309-01.png)
ご覧のように、「使用日数カウントのリセット日」をリセットしたことがないため、リストされているオブジェクトはすべてNULLになっています。そのリセット日がnullの場合、SQLステートメントはオブジェクトの作成日を使用して、オブジェクト作成後の経過時間や、「Days Available(利用可能日数)」列および「Usage Percentage(使用パーセンテージ)」列の計算を行います。
ORDER BY節を変更すれば、使用された回数が最も少ないオブジェクトから順に、結果をリストすることができますが、私のショップでは、使用されていないオブジェクトが「大量に」あるため、降順の方が適切と考えました。本番環境では、その逆の方が適切な場合もあるしょう。
オブジェクト作成後の経過時間(Object Age)と使用可能日数(Days Available)
上述のSQLステートメントで、「OBJAGE(オブジェクト作成後の経過時間(日数))」という名前の列と、「DAYS_AVAILABLE(オブジェクトが利用可能となっていた日数)」という名前の列とでは、日数が1日だけ異なっています。そうなる理由は、たとえば、オブジェクトが「昨日」作成されたとしたら、「今日」現在で、そのオブジェクトの経過日数は1日ということになります。しかし、そのオブジェクトは「昨日」と「今日」の2日間にわたって利用可能となっているため、利用可能日数は2日となるからです。それら2つのうち、後者は、使用日数のパーセンテージ(Percentage of Days Used)の計算で使用されます。
よろしいでしょうか、皆さん。私は、決して卓越したSQL開発者などではありませんが、一日中SQL関数を書いては保守を行っている、そこそこのプログラマーです。先日、私は、「使用日数(Days Used)」オブジェクト プロパティについてまったく誤解していたことに気付きました。そして、読者の皆さんのおかげで、このプロパティがどのようなものなのかについて、そしてそのプロパティを使用して、どのオブジェクトが実質的に使用されていないのか調べる方法について、理解を深めることができました。
ただそれだけのことです。