前回は中間テーブルの入門用として、用意するレコードもたった一つといった非常に初歩的な要件での実装例を紹介した。今回はもう1ステップ進んだチュートリアルとして、中間テーブルにあらかじめ用意するレコード数の計算方法と、Webアプリケーションからの計算結果転記方法を紹介しよう。

中間テーブルに用意するレコード量算出の計算式

あらかじめ集計をおこなっておき、その結果を数字フィールドとして格納しておく……計算フィールドや集計フィールドでは実現できない高パフォーマンスを実現する実装法として、前回中間テーブルによる集計の方法を紹介した。

中間テーブルにはあらかじめ集計の結果を格納するレコードをすべて作成しておく。このレコード数は集計の切口によって上下するため、設計前に「どのような集計をしたいか」を検討する必要がある。実際に要件としてありがちな集計の例をあげてみよう。

集計例

  1. 月単位で全体をとおした売上/仕入/粗利金額や在庫数を集計したい
  2. 月単位で社員(ユーザ)がどれだけ残業しているかを集計したい
  3. 年単位である顧客にどの商品がいくつ売れているのかを集計したい

中間テーブルに用意するレコード数の計算式は「集計結果を保存しておく期間 * 切口の対象となるデータの上限値」で求める。

集計結果を保存しておく期間

集計切口の時間軸が細かくなればなるほど、値が増える。たとえば5年分のデータを保存しておきたいとした場合、計算式は次のとおりとなる。

  • 年単位で集計したい: 5
  • 月単位で集計したい: 12 * 5 = 70
  • 日単位で集計したい: 365 * 5 = 1825

切口の対象となるデータの上限値

システムに登録される可能性のあるデータのシリアル上限値を指す。たとえばあらかじめ「Webアプリケーションの利用者数は100人未満」とわかっているならば、ユーザマスタのシリアル上限値は100(余裕をもって増やしておくのも良い)となる。上限値を多く取りすぎるとレコード数が莫大になり、メンテナンスにかかる時間が増大する可能性があるので実装前に要件を確認・確定させておくことが大切だ。

これら2つの計算式をもとに、先にあげた集計例のレコード数を算出してみよう。集計結果を保存しておく期間は「5年」、データの上限値は「ユーザ数=100」「顧客数=100」「商品数=1000」と定義した。

中間テーブルにあらかじめ用意するレコード数

  1. 月単位で全体をとおした売上/仕入/粗利金額や在庫数を集計したい
    → 12(月) * 5(年) = 70

  2. 月単位で社員(ユーザ)がどれだけ残業しているかを集計したい
    → 12(月) * 5(年) * 100(ユーザ数上限) = 6,000

  3. 年単位である顧客にどの商品がいくつ売れているのかを集計したい
    → 5(年) * 100(顧客数) * 1000(商品数) = 500,000

集計例(1)の中間テーブルイメージ図。「年」「月」をキーとし、売上/仕入テーブルにレコードが登録される度に中間テーブルへ差分の計算結果を転記する

集計内容によっては、かなりのレコード数になることもある。年や月、ユーザや顧客名称といった検索に使用する可能性のある項目にはかならず「全索引を作成する」オプションを指定しておこう。

おなじみ索引設定のオプション。うっかり索引の設定をせずにレコードを作成してしまうと、索引の再設定で時間がかかるので忘れずにチェックしておこう

Webアプリケーションから中間テーブルへ値を書き込む

前回は「Web公開に対応したスクリプトステップで構成したFileMakerスクリプト」を使うことで中間テーブルへ値を書き込んだ。PHPからはレコードの作成時にこのFileMakerスクリプトを起動させることで中間テーブルへ計算結果が転記される。サンプルコードは次のとおり。

PHPファイル - fm_new_fmscript.php

<?php

include_once('./fx/FX.php');
include_once('./fx/server_data.php');

$data = new FX($serverIP, $webCompanionPort, $dataSourceType, $scheme);
$data->SetDBData($databaseFileName,'(処理レイアウト名)');
$data->SetDBUserPass($webUN,$webPW);
$data->SetCharacterEncoding('utf8');
$data->SetDataParamsEncoding('utf8');
/*
 * フィールドへの入力 ..
 */
$data->AddDBParam('-script' , '(中間テーブルへの転記スクリプト名)');
$dataSet = $data->FMNew();

?>

FileMakerスクリプトを起動させて値を転記させる以外に、PHPを使用して値を転記させる方法もある。PHPの処理手順は次のとおりだ。

  1. レスポンスレイアウトに「中間テーブルのレコードIDを格納したフィールドを配置してあるレイアウト」を指定し、レコードを登録する
  2. PHPで各種の計算をおこなう
  3. 1で取得したレコードIDを使用し、2の結果を中間テーブルへ書き込む

実際のPHPコードは次のとおり。

PHPファイル - fm_new_php.php

<?php

include_once('./fx/FX.php');
include_once('./fx/server_data.php');

$data = new FX($serverIP, $webCompanionPort, $dataSourceType, $scheme);
$data->SetDBData($databaseFileName,'(処理レイアウト名)', 1, '(中間テーブルのレコードIDフィールドが配置されているレイアウト名)');
$data->SetDBUserPass($webUN,$webPW);
$data->SetCharacterEncoding('utf8');
$data->SetDataParamsEncoding('utf8');
/*
 * フィールドへの入力 ..
 */
$dataSet = $data->FMNew();

if ( '0' === (string)$dataSet['errorCode'] )
{
    // 中間テーブルへ値を転記
    $commit = new FX($serverIP, $webCompanionPort, $dataSourceType, $scheme);
    $commit->SetDBData($databaseFileName,'(中間テーブルのレイアウト名)', 1 );
    $commit->SetDBUserPass($webUN,$webPW);
    $commit->SetCharacterEncoding('utf8');
    $commit->SetDataParamsEncoding('utf8');
    /*
     * 中間テーブルへ転記する値の計算、フィールドへの入力 ..
     */
    $data->AddDBParam('-recid' , $dataSet['data'][key($dataSet['data'])]['(中間テーブルのレコードIDフィールド名)'][0]);
    $commitSet = $commit->FMEdit();

    if ( '0' === (string)$dataSet['errorCode'] )
    {
        /*
         * 正常処理 ..
         */
    }
    else
    {
        /*
         * エラー処理 ..
         */
    }
}
else
{
    /*
     * エラー処理 ..
     */
}

?>

FileMakerスクリプトを使用した場合、FileMaker側でどういった処理がおこなわれているかを把握しにくい。これらのアクションをFileMakerスクリプトではなくPHP側でおこなうことで各種のロギングやデバッグ作業、ファイルシステムを使用した排他処理やほかの処理との連携がしやすくなる。

FileMakerスクリプトを使う方法、PHP側で計算転記する方法どちらにもメリットデメリットがある。

FileMakerスクリプトを使って中間テーブルへ転記する

メリット

  • FileMakerに詳しければ、PHPにあまり精通していないデベロッパでも実装が可能
  • 比較的短期間での実装が可能

デメリット

  • スクリプトの処理進捗をPHP側に渡せない
  • FileMakerサーバの処理による遅延、FileMakerスクリプトの結果返り値の制約などから排他処理の実装がややむずかしい

PHPで中間テーブルへ転記する

メリット

  • すべての処理をPHP側でおこなうため、デベロッパはPHPコードだけを見れば処理の全体像がわかる
  • ほかの処理との連携や排他処理を実装しやすい

デメリット

  • FileMakerスクリプトと比較すると実装に時間がかかる
  • 複数の中間テーブルへ値を転記する場合、エラー処理が複雑になりやすい

中間テーブルの用途は場面によってさまざまだ。それぞれに応じた最適な手段を選択しよう。