大規模なデータセットを使用するアプリのスケーリングを効果的に行えば、便利なユーザー インターフェースを維持しつつ、同期の時間を短縮できます。アプリが同期を行う際は、データがデータベースからデバイスにコピーされるため、ユーザーはアプリ内のデータに簡単にアクセスできます。デフォルトでは、アプリの初回起動時に、アプリに関連するすべてのデータが同期されます。デフォルトのこの設定は、小規模から中規模のデータセットを使用するアプリに対しては効果的ですが、データセットが膨大な場合は同期に時間がかかることになります。
水平スケーリングは、データをアプリに同期する方法とタイミングをアプリ作成者が構成するための手法です。この手法では、データがバケットに分割されます。Bucket 1 にはユーザーがアプリの使用を開始するにあたって必要なデータが含まれます。Bucket 2 には Bucket 1 でユーザーが選択するデータに基づく追加データが含まれます。前のバケットでの選択に基づいたドリルダウンをくりかえすことにより、このモデルは無限にスケールできます。
例として、ユーザーがデザートのメニューを確認するアプリについて考えてみましょう。この架空の会社では、60,000 を超えるユニークでおいしいデザートを提供しています。データセット全体を読み込むには多少時間がかかりますが、データをうまくバケットに分割することにより、同期にかかる時間を大幅に短縮し、パフォーマンスを改善できます。
テーブルの構造
ワークフロー
作成するアプリのユーザー エクスペリエンスに基づいて、テーブルを 3 つのバケットに分割しました。
Bucket 1
ユーザーがアプリを開くとホームページが表示され、ユーザーはデザートの種類を選択できます。この時点で AppSheet は Type テーブルのみを同期します。選択したらユーザーは [Go] をクリックして次に進みます。
Bucket 2
AppSheet は Dessert テーブルからすべての行を読み込みます。Type はユーザーが Bucket 1 から選択したものと一致します。最初のフィルタを使用することで、同期の条件を 60,000 すべてから大幅に減らすことができました。
Bucket 3
AppSheet は Bucket 2 で読み込まれた Desserts のサブセットに関連する Reviews と Recipes のみを読み込みます。ここでも同期中に読み込まれるレコードの数を大幅に減らすことができます。
実装
ユーザー設定とセキュリティ フィルタは AppSheet のツールで、水平スケーリングを可能にします。
ユーザー設定はフォームビューで表示され、ユーザーはフォームで選択と保存ができます。これらの値には、アプリ全体で数式を使用してアクセスできます。
セキュリティ フィルタは数式で、同期中に読み込まれるデータを制限します。ユーザーが選択したユーザー設定に基づいてセキュリティ フィルタを作成することで、データをフィルタして選択した Type のみを取得できます。フィルタの条件に一致しないデータは同期に含まれません。
例: Dessert テーブルで使用されるセキュリティ フィルタ
= [Type ID]=USERSETTINGS("Type")
例: Review テーブルで使用されるセキュリティ フィルタ
= IN([Dessert ID], Dessert[Dessert ID])
スライスを使用した別のアプローチ
前述の実装には制限があり、ユーザーが Type を選択するまでどのデザートも表示されません。デザートの一覧を検索することによりユーザーが最初の選択をできるようにしたい場合があります。
例: デザートの一覧が表示されるよう変更されたユーザー設定
デザートの全一覧を検索するにあたって課題が生じます。デザートの全一覧を表示するにしても、すべてのデザートに関連する Reviews と Recipes をすべて読み込むことはしたくないためです。これは、スライスを使うことで可能になります。
スライスとは、データのサブセットのことです。データテーブルと同様、サブセットは AppSheet 全体で使用できます。デザートのテーブルのスライスを作成して、ユーザーが選択した Search Method に基づく Row フィルタ条件を適用できます。ユーザーが Type でフィルタする場合、スライスには Type に一致するすべてのデザートが含まれます。ユーザーが全一覧から 1 つのデザートを選択する場合、スライスには 1 つのデザートだけが含まれます。
例: Dessert スライスのフィルタ式
SWITCH(USERSETTINGS("Search Method"), "Type", [Type ID]=USERSETTINGS("Type"), "Full Dessert List", [Dessert ID]=USERSETTINGS("Dessert"), FALSE)
Reviews と Recipes のセキュリティ フィルタは、Dessert ID がスライス内の内容と一致する行のみを選択します。
例: Review テーブルと Recipe テーブルで使用されるセキュリティ フィルタ
= IN([Dessert ID], Dessert Slice[Dessert ID])
例: 更新されたテーブルの構造
ユーザーのメールアドレスに基づく自動選択
このコンセプトには別の手法もあります。この方法では、アプリケーションの読み込み時にデータのサブセットを自動選択します。一般的なユースケースでは、ログインしたユーザーのメールアドレスに基づいてフィルタします。これは、ユーザーが自分に関係するレコードのみを確認したい場合に効果的です。
例: ユーザーのメールアドレスのセキュリティ フィルタ
= [メール列]=USEREMAIL()
子テーブルをフィルタして USEREMAIL() フィルタをパスした親テーブルの行に関連するデータのみを読み込むことで、さらにパフォーマンスを改善することができます。子テーブル内の参照列の Primary Key がフィルタされた親テーブルの Primary Key と一致するかどうかを確認することで可能になります。これには、次のような IN() ステートメントを使用できます。
例: 子テーブルをフィルタする IN() ステートメント
= IN([Parent ID], Parent Table[Parent ID])
ユーザーのメールアドレスに基づいたセキュリティ フィルタの適用について詳しくは、ユーザーを独自のデータに制限するをご覧ください。
パーティショニング
データのスケーラビリティを実現する方法の記事で触れたように、スプレッドシート ベースのアプリの場合、セキュリティ フィルタによるパフォーマンスの改善幅は限られます。セキュリティ フィルタが適用される前にスプレッドシート全体を読み込まなければならないためです。スプレッドシートを使用する場合、パフォーマンスを改善し、最大データサイズの制限を回避できるパーティショニングは強力なツールです。
制限事項
水平スケーリングにおいて制限があるのは、ユーザー設定を更新するためのインターフェースです。ユーザーはメニューからこれらの設定にアクセスする必要があります。ユーザー設定ビューをユーザーのホームページとして設定し、アプリに入る前のユーザーに最初の選択をしてもらうことができます。しかし、最初に選択した内容を後で更新するには、ユーザーはメニューからユーザー設定に戻る必要があります。