プラットフォームパフォーマンスのベストプラクティス

プラットフォームパフォーマンスのベストプラクティス

お知らせ:当社は、お客様により充実したサポート情報を迅速に提供するため、本ページのコンテンツは機械翻訳を用いて日本語に翻訳しています。正確かつ最新のサポート情報をご覧いただくには、本内容の英語版を参照してください。

Zoho Creator は、1 つの要件に対して複数の解決方法が利用できるプラットフォームです。ケースによっては、あるアプローチの方がパフォーマンスや効率の面で優れている場合があります。この記事では、同じ要件を実現する方法が複数ある場合に、最適な方法を見つけるための実践的なポイントを解説します。

パフォーマンス向上のための Do / Don't

要件
避けるべきこと
推奨される解決方法
複数フォームで同じ項目を扱う場合
同じデータのために、重複する項目を追加しないでください。
ルックアップ項目を使ってフォーム間のリレーションを構成してください。
比較処理
バックエンドでの計算量が多くなり、パフォーマンス低下につながるため、可能な限り「contains」演算子の使用は避けてください。「equals」組み込み関数の方が比較的高パフォーマンスです。
Deluge の組み込み関数「equalsIgnoreCase」を使用してください。
複数レコードの更新
すべてのデータを取得し、コレクションをループして各レコードを個別に更新する方法は避けてください。各更新は個別のトランザクションとして扱われるため、オーバーヘッドが増え、利用可能なトランザクション数をすぐに消費してしまいます。
一括更新Deluge タスクを使用し、1 回のトランザクションで複数の項目を更新してください。
データコレクションに対する処理
すべてのデータを取得してからループして処理を行ったり、すべてのデータを取得した後に IF 条件で絞り込む方法は避けてください。
取得条件を指定し、必要なデータのみを取得するようにしてください。

取得条件に、'必須' や '重複値なし' に設定された項目を使用すると、パフォーマンスが向上します。同様に、システム項目(追加日時、更新日時など)を条件に利用することも、パフォーマンス改善に役立ちます。
データをループして項目値を取り出し、計算を行う方法は避けてください。
取得タスク内で直接集計関数を使用してください。例えば、sum 関数を使えば、データ取得時に合計値を計算でき、取得後に別途計算する必要がなくなります。
同様に、値の取得には、データをループして取り出すのではなく、取得処理の一部として getAll() を使用してください。
大量のデータを処理する際に、レポート上のカスタムアクションボタンを使用することは避けてください。これらは同期的に実行されるため、通常の利用時のアプリケーションパフォーマンスに影響を与える可能性があります。
そのようなスクリプトは、代わりに スケジュール機能を使用して、営業時間外に実行するようにしてください。
API コールの実行
コードブロック内に API スクリプトが含まれている場合、ワークフローは次のステートメントに進む前に API レスポンスを待機します。このような API コールをユーザー操作中に実行すると、ユーザーにとって目に見える遅延が発生する可能性があります。
API コールを含むワークフローは、営業時間外に実行されるようスケジュールしてください。

メモ: レスポンスを待たずにスクリプトを実行できる非同期タスクも開発中です。リリース状況を確認することができます。
既に用意されている Deluge タスクで実行できる処理に、API を使用しないでください。
API コールに依存するのではなく、Deluge タスクを使用し、その後に Function を呼び出して実行後のロジックを処理してください。
ページ内での計算
ページスクリプトなど、リアルタイムでユーザーの同時アクセスが多くなる可能性が高い場面で計算処理を行うことは避けてください。これらはページ処理中に実行されます。
そのような計算はワークフロー側に移し、ページでは計算済みの値を表示するだけにしてください。
同一フォーム内の項目に対する計算・連結
必要な項目がすべて同じフォーム内にある場合、スクリプトで計算や文字列連結を行うことは避けてください。
数式項目を使用してください。入力中にフォーム内で計算が行われるため、フォーム送信後に同じデータを再取得して計算・値の設定を行う方法よりも効率的で、不要なオーバーヘッドを避けられます。
データ更新用スケジュールの設定
「追加日時」などの項目を基準に実行されるフォームベースのスケジュールでは、フォーム内のすべてのデータを更新しないでください。複数ユーザーが同時にデータを追加したり、データをインポートしたりすると、複数のスケジュールが並行して実行され、一括更新を試みることでタイムアウトが発生する可能性があります。この問題は、複数のスケジュールが同時にトリガーされる可能性があるあらゆるシナリオで起こり得ます。
一括更新ではなく、現在対象となるデータのみを更新するようにしてください。
他サービスの API 利用
複数の API コールを組み合わせて複雑なロジックを実装するのではなく、必要な計算を 1 回、または少ない回数の API コールで処理できる専用キーが用意されている場合は、それを利用してください。 例えば Zoho Books では、複数の API を呼び出してデータをループし、請求書の総数や合計金額を計算する代わりに、response_option キーを使用して直接計算を行うことができます。これにより、重量級のスクリプトを避け、API コールの回数も削減できます。

スクリプト最適化の例

例 1

❌ 次のようにデータを取得してから各レコードをループ処理する方法は、最も効率的とは言えません。
  1. fetchInvoices = Invoice_form[<criteria>];
  2. if(fetchInvoices。件数() > 0)
  3. {
  4. for each 請求書 in fetchInvoices
  5. {
  6. <操作>
  7. }
  8. }
✅ 取得処理の一部として、直接レコードをループする方が効率的です:
  1. for each 請求書 in Invoice_form[<criteria>];
  2. {
  3. <操作>
  4. }

例 2

❌ 次のように、値を取得するためだけにレコードをループする方法は非効率です。
  1. paymentList=List(); // リスト変数の作成
  2. for each 請求書 in PaymentAgainstInvoice[<criteria>] // 取得済みデータのループ処理
  3. {
  4. paymentList。追加する(請求書。ID); // 各ループで ID を取り出し、リスト変数に追加
  5. }
✅ 同じ処理は、組み込み関数を使うことで効率的に実行できます。
  1. paymentList = PaymentAgainstInvoice[<criteria>].ID。getAll(); // 上記 3 つの処理を 1 つのトランザクションで実行

例 3

❌ 同様に、以下のスクリプトのようにデータをループして件数を取得する代わりに:
  1. recordcount = 0
  2. fetchInvoices = Invoice_form[<criteria>];
  3. for each lineitemcount in fetchInvoices
  4. {
  5. recordcount = recordcount + 1;
  6. }
✅ 代わりに、次のように集計関数を使用します:
  1. recordcount = Invoice_form[<criteria>].件数(ID);

例 4

❌ 先にデータを挿入し、その後で条件チェックを行ってから挿入済みデータの値を変更する。
  1. billID = insert into 受取請求書
  2. [
  3. Added_User=Zoho。loginuser
  4. Total_Price=Total_Price
  5. Bill_Status=Bill_Status
  6. ];
  7. fetchBill = 受取請求書[ID == billID];
  8. if(patient_Type == '無料')
  9. {
  10. fetchBill。Total_Price=0;
  11. fetchBill。Bill_Status='完了済み';
  12. }

✅ 代わりに、データを挿入する前に条件チェックを行います:
  1. if(patient_Type == '無料')
  2. {
  3. Total_Price=0;
  4. Bill_Status='完了済み';
  5. }
  6. billID = insert into 受取請求書
  7. [
  8. Added_User=Zoho。loginuser
  9. Total_Price=Total_Price
  10. Bill_Status=Bill_Status
  11. ];


例 5

❌ データを更新して更新後ロジックをトリガーするために API を使用する。
  1. rec = Form[ID = <record_ID>];
  2. rec。Single_line = <値>;
  3. updateapi = Zoho。creator。updateRecord(<owner_name>, <app_link_name>, <report_link_name>, rec。ID, <new_input_values>, <other_api_params>, <connection_link_name>);

✅ 代わりに、データ更新 Deluge タスクを使用し、関数を使って更新後ロジックをトリガーします:
  1. rec = Form[ID = <record_ID>];
  2. rec。Single_line = <値>;
  3. rec。番号 = <値>;
  4. functionscript = thisapp.<function_with_on_success_code>(int rec。ID);

パフォーマンス向上の一般的なヒント

  1. スクリプトの過度なネストは避けてください。
  2. 複数の独立した If 条件ではなく Else-If 構造を使用し、一致する条件が見つかった時点で評価が停止するようにします。
  3. 可能な限り組み込み関数を使用してください。これらはパフォーマンス向上のために最適化されています。
  4. Try-Catchステートメントを使用して、コード内の例外を処理できます。
  5. リアルタイムで実行する必要のないタスクは、スケジュールに移動するか、非同期タスクで処理するようにします。
  6. バッチ ワークフロー機能を使用して、大量または反復的な処理を効率的かつ定期的、自動的にデータに対して実行します。データは設定したスケジュールに基づいて処理され、最大 1000 件までの小さなバッチに分割できます。これにより、大量のデータを一度にループ処理することを避け、営業時間外に処理を行うことで、全体的な効率を向上できます。
  7. Environments機能を使用して変更内容をテストし、営業時間外に本番環境へ反映することで、ユーザーへの影響を最小限に抑えます。
  8. 実装前にアプリケーションとワークフローを十分に設計・モデリングしてください。多くのパフォーマンス問題は、アプリケーションロジックの設計不備に起因します。
  9. Pages など、複数ユーザーの共通の操作ポイントとなるコンポーネントから書き込み処理を行うことは推奨されません。これらは同時に複数の書き込み処理をトリガーし、パフォーマンス問題を引き起こす可能性があります。同様に、自動採番項目でも、高い同時実行性により連番生成が同時に行われることで、遅延や競合が発生する場合があります。
  10. システム変数(Zoho。appuri や Zoho。appname など)を活用し、値をハードコードしないようにします。これにより、アプリケーションリンク名や担当者名が変更された場合でも自動的に反映されます。これは、コンポーネントを埋め込むために HTML ページ内で Deluge スクリプトを使用する際に特に有用です。
  11. 可能な限りスクリプトではなく組み込み機能を活用してください。例えば:
    1. 値を逆方向に関連付けるスクリプトを記述する代わりに、項目プロパティで双方向ルックアップを使用する
    2. 初期値はスクリプトではなく項目プロパティで設定する
    3. 計算が必要な場合は、可能な限りスクリプトではなく数式項目を使用する
  12. 条件にインデックス付き項目を使用すると、関連データをより高速に取得できます。インデックス作成はバックエンド処理となるため、有効化の支援が必要な場合は support@zohocreator.com までお問い合わせください。

ロック、デッドロック、タイムアウト

Zoho Creator では、次のような競合シナリオを回避するための仕組みを採用しています:
  1. ロック: 特に高い同時アクセスがある環境で、データの完全性と一貫性を維持するための重要かつ標準的な手順です。例えば、あるユーザーがデータを編集している間は、別のユーザーが同じデータを同時に変更できないようにする必要があります。そうしないと、データ破損につながる可能性があります。同様に、フォーム内で項目の追加・削除・更新(必須項目への変更など)を行っている間は、そのフォームに対するフォームレベルのクエリがロックされます。この期間中に対象フォームに対して行われたクエリは、フォームの変更が完了してロックが解除されるまで、実行に時間がかかったり、タイムアウトにより失敗したりする場合があります。

  2. デッドロック:2 つ以上のリクエストが互いにロックの解除を待ち合うことで依存関係のループが発生し、その結果いずれかのリクエストが失敗する状況です。例えば、2 つのワークフローがそれぞれ 2 件のデータ(データ A とデータ B とします)を更新するケースを考えます。ワークフロー 1 が先にデータ A、次に B を更新し、ワークフロー 2 が先にデータ B、次に A を更新するような場合、両方のワークフローが同時に実行されるとデッドロックが発生する可能性があります。このとき、ワークフロー 1 は A を更新してから B を待ちますが、B はワークフロー 2 が更新処理中のためロックされています。一方、ワークフロー 2 は B を更新した後で A を待ちますが、A はワークフロー 1 によってロックされており、ワークフロー 1 は B の更新が完了するまでデータ A を解放できません。その結果、いずれかのワークフローが失敗します。この問題の解決策は、データの更新順序を一貫させることです。つまり、両方のワークフローで「先にデータ A、次にデータ B」を更新するように構成します。

  3. タイムアウト: リクエストが長時間待機した場合に発生します。これは、接続の問題、ロック解除待ち、レスポンス待ち、またはトランザクションが定められた時間制限を超えて実行されている場合などが原因となります。

    Zoho Creator におけるタイムアウトの詳細:
    タイムアウト
    時間制限
    説明
    データロック タイムアウト
    30 秒
    リクエストがデータロックの解除を待機できる最大時間。この制限を超えると、リクエストは失敗します。
    バッチ ワークフローのトランザクション タイムアウト
    1 分
    バッチ ワークフローが実行できる最大時間。この制限を超えると、トランザクション全体がロールバックされます。
    通常ワークフローのトランザクション タイムアウト
    5 分
    その他すべてのワークフロータイプが実行できる最大時間。この制限を超えると、トランザクション全体がロールバックされます。
    外部 API コールの読み取りタイムアウト
    40 秒
    API コールがタイムアウトする前にレスポンスを返すことができる最大時間。

ベストプラクティス

  1. ロックの保持時間を最小限に抑えるため、リクエストの処理時間はできるだけ短く保ってください。
  2. Environments を使用してワークフローをテストし、実行時間を確認して問題の可能性を排除します。また、各ワークフローで影響を受けるデータ件数も確認してください。この件数を少なく保つことで、処理時間を短縮できます。
  3. 大きなコードブロックは、小さく独立したチャンクに分割してください。
  4. 一貫したロック順序: フォームデータを編集するワークフローでは、循環待ちを避けるために、常に同じ順序でデータを更新するようにしてください。
  5. 同一ワークフロー内で過度に多くの API コールを行うことは避けてください。ロックの保持時間が長くなり、タイムアウトの原因となる可能性があります。

アプリのパフォーマンスの追跡

アプリのパフォーマンス
通常、すべてのアプリ画面は 2 秒以内に読み込まれるよう最適化されています。これを大きく超える遅延がある場合は、パフォーマンス上の問題が発生している可能性があります。ただし、これはアプリの複雑さ、バックエンドで実行されているタスクの数、コードの最適化状況などにも左右されます。効率的なアプリケーションロジックがなければ、アプリケーションを最適な状態で動作させることはできません。さらに、パフォーマンス低下の原因となっている可能性のある操作失敗を特定するために、アプリケーションログを確認できます。

プラットフォームの稼働状況
ステータスページでは、プラットフォームの稼働状況をリアルタイムで確認できます。このページでは、サービスの稼働状況、現在の応答時間、およびプラットフォームのパフォーマンス指標を確認できます。応答時間の急激な増加は、パフォーマンスの問題を示している可能性があります。これにより、パフォーマンス低下がサービス全体で発生しているのか、特定のサービスに限定されているのかを判断できます。後者の場合は、アプリケーションロジックのさらなるデバッグやコードの最適化が必要になることがあります。