次の方法で共有


コードの最適化

キャンバ スアプリが多様なビジネス要件に合わせて進化するにつれ、最適なパフォーマンスを維持することが重要な課題となっています。 キャンバス アプリ内のデータ処理、ユーザー インターフェイスの設計、機能の複雑さにより、コードの最適化には微妙なアプローチが必要になります。

キャンバス アプリが複雑になるにつれ、開発者はデータ検索、式の複雑さ、レンダリング速度に関する課題に直面します。 堅牢な機能と応答性の高いユーザー インターフェイスのバランスをとる必要があることから、コード最適化に対する体系的なアプローチを採用することの重要性が強調されます。

Power Fx 式の最適化

With 関数

With 関数は単一レコードの数式を評価します。 数式では、値を計算したり、データの変更や接続の操作などのアクションを実行したりすることができます。 With を使用して、複雑な数式を小さな名前の付いたサブ数式に分割することで、複雑な数式を読みやすくします。 これらの名前付きの値は、With のスコープに限定された単純なローカル変数のように機能します。 With を使用すると、自己完結型で理解しやすく、宣言式のコンテキストで使用できるため、コンテキスト変数やグローバル変数よりも推奨されています。 With 関数についての詳細情報

With 関数を使用した Power Fx 式のスクリーンショット

Concurrent 関数

Concurrent 関数を使用すると、コネクタや Dataverse の呼び出しがある場合に、同じプロパティで指定した複数の数式を同時に評価できます。 通常、複数の数式は、; (セミコロン) 演算子を使用して連結することにより評価します。これによって、各数式は順番に評価されます。 Concurrent 関数では、; 演算子を使用した後でも、アプリがプロパティに含まれる数式をすべて同時に評価します。 この同時実行機能によって、ユーザーは同じ結果を得るまでの待機時間を短縮できます。 前の呼び出しが完了するまで、データ呼び出しが開始されない場合、アプリはすべての要求時間の合計を待機する必要があります。 データ呼び出しが同時に開始される場合、アプリは最長の要求時間だけ待機する必要があります。 Concurrent 関数についての詳細情報

Concurrent(
    ClearCollect(colAccounts1, Accounts),
    ClearCollect(colUsers1, Users),
    ClearCollect(colEnvDef1, 'Environment Variable Definitions'),
    ClearCollect(colEnvVal1, 'Environment Variable Values')
);

結合関数

Coalesce 関数はその引数を順番に評価し、空白または空の文字列ではない最初の値を返します。 この関数を使用して、空白の値や空の文字列を別の値に置き換えますが、空白でない文字列や空でない文字列の値は変更しません。 すべての引数が空白または空の文字列の場合、この関数は空白を返すので、Coalesce は空の文字列を空白値に変換するのに適した方法になります。

例:

If(Not IsBlank(value1), value1, Not IsBlank(value2), value2)

値 1 と値 2 を 2 回評価する必要があります。 この関数は次のように簡略化できます:

Coalesce(value1, value2)

IsMatch 関数

IsMatch 関数は、通常文字、事前定義済みのパターン、または正規表現 が含まれたパターンにテキスト文字列が一致するかどうかをテストします。 IsMatch 関数についての詳細情報

たとえば、この式は米国の社会保障番号と一致します:

IsMatch(TextInput1.Text, "\d{3}-\d{2}-\d{4}")

正規表現の説明:

\\d 任意の数字 (0 ~ 9) と一致します。

{3} は、前の桁のパターン (\d) がちょうど 3 回出現するように指定します。

- ハイフン文字と一致します。

{2} は、前の桁のパターン (\d) がちょうど 2 回出現するように指定します。

{4} は、前の桁のパターン (\d) がちょうど 4 回出現するように指定します。

IsMatch のその他の例:

IsMatch(TextInput1.Text, "Hello World")
IsMatch(TextInput1\_2.Text, "(?!^\[0-9\]\\\*$)(?!^\[a-zA-Z\]\\\*$)(\[a-zA-Z0-9\]{8,10})")

アプリ OnStart の最適化

キャンバス アプリの OnStart プロパティは、アプリの起動時に発生するアクションを定義する上で重要な役割を果たします。 このプロパティにより、アプリ開発者はグローバル初期化タスクを実行し、変数を設定し、アプリの起動プロセス中に 1 回だけ実行されるアクションを実行できます。 レスポンシブで効率的な キャンバス アプリを作成するには、OnStart プロパティを理解して効果的に活用することが不可欠です。

推奨されるアプローチは、変数セットアップを名前付き数式に移行することによって App.OnStart 関数を合理化することです。 名前付き数式、特にアプリのライフサイクルの初期に構成された数式が有利であることがわかります。 これらの数式は、データ呼び出しに基づいて変数の初期化を処理し、コードに、よりクリーンで整理された構造を提供します。 詳細情報 大規模で複雑なキャンバスアプリを構築 - Power Apps | Microsoft Learn

注意

OnStart プロパティは 命令型です これは、最初の画面が表示される前に実行する必要がある作業の順序付きリストです。 をしなければならないかだけでなく、作業指示書に基づいて いつ その作業を行わなければならないかについても非常に具体的であるため、そうしなければ行えるはずの最適化の順序変更や延期が制限されます。

開始画面

App.OnStartNavigate 関数呼び出しを含んでいる場合、たとえそれが If 関数内にあり、めったにコールされないとしても、App. の実行を完了させなければなりません OnStartアプリの最初の画面を表示する前に。  App.StartScreen は最適化をブロックせずに、どの画面を最初に表示するかを示す新しい宣言的な方法です。

StartScreen プロパティを設定すると、App.OnStart が完了する前に最初の画面が表示されます。 App.StartScreen declares は、どのスクリーンオブジェクトを最初に表示するかを宣言します。

次のようなコードは記述しません:

App.OnStart = Collect(OrdersCache, Orders);
If(Param("AdminMode") = "1", Navigate(AdminScreen), Navigate(HomeScreen))

コードを次のように変更します:

App.OnStart = Collect(OrdersCache, Orders);
App.StartScreen = If(Param("AdminMode") = "1", AdminScreen, HomeScreen)

詳細については、<https://Power Apps.microsoft.com/en-us/blog/app-startscreen-a-new-declarative-alternative-to-navigate-in-app-onstart/> をご参照ください。

警告

StartScreenOnStart の依存関係を避けてください。 グローバル変数を参照する名前付き書式を参照すると、StartScreen が正しく適用されない競合状態が発生する可能性があります。 注記: StartScreen と OnStart の間に依存関係があってはなりません。 StartScreen ではグローバル変数の参照をブロックしますが、名前付きの数式を参照することはできます。名前付きの数式はグローバル変数を参照するため、StartScreen が正しく適用されない競合状態が発生する可能性があります。

名前付き計算式

名前付き数式は、App.Formulas セクションで定義できる静的または定数式です。 App.Formulas で宣言すると、アプリ内のどこでも使用でき、値は常に最新の状態に保たれます。 Power Apps の名前付き数式は、プラットフォームによって自動的に管理・更新される値や値のセットを定義することができます。 この機能により、価値の計算と維持の責任が開発者から Power Apps に移り、開発プロセスが合理化されます。 Power Apps の名前付き数式は、アプリのパフォーマンスと保守性を大幅に向上させる強力な機能です。

名前付き数式は、アプリのテーマの宣言にも使用できます。 企業向けアプリを構築する場合、アプリに共通のテーマを持たせ、一貫性のある外観とユーザーエクスペリエンスを実現したいケースが一般的です。 テーマを作成するには、App OnStart で宣言する必要がある変数が数十から数百存在します。 これにより、コードの長さとアプリの初期化時間が増加しました。

最新のコントロールはテーマ設定にも大きく役立ち、テーマ設定を処理するために顧客が記述するロジックを削減するのにも役立ちます。 最新のコントロールは現在プレビュー段階です。

たとえば、App.OnStart 上の次のコードを App.Formulas に移動することで、グローバル変数宣言の起動時間を短縮できます。

Set(BoardDark, RGBA(181,136,99, 1));
Set(BoardSelect, RGBA(34,177,76,1));
Set(BoardRowWidth, 10);                      // expected 8 plus two guard characters for regular expressions.
Set(BoardMetadata, 8 \* BoardRowWidth + 1);   // which player is next, have pieces moved for castling rules, etc.
Set(BoardBlank, "----------------------------------------------------------------\_00000000000000");
Set(BoardClassic, "RNBQKBNR\_\_PPPPPPPP------------------------\_--------\_\_pppppppp\_\_rnbqkbnr\_\_0000000000");

コードは次のように App.Formulas に移動できます:

BoardSize = 70;
BoardLight = RGBA(240,217,181, 1);
BoardDark = RGBA(181,136,99, 1);
BoardSelect = RGBA(34,177,76,1);
BoardRowWidth = 10;                      // expected 8 plus two guard characters for regular expressions
BoardMetadata = 8 \* BoardRowWidth + 1;   // which player is next, have pieces moved for castling rules, etc.
BoardBlank = "----------------------------------------------------------------\_00000000000000";
BoardClassic = "RNBQKBNR\_\_PPPPPPPP------------------------\_--------\_\_pppppppp\_\_rnbqkbnr\_\_0000000000";

もう一つの例は inn の設定 Lookups です。 ここでは、ルックアップ式を変更して、 Office 365 ではなく、Dataverse からユーザー情報を取得する必要があります。 コード全体を変更せずに変更が必要な箇所は 1 か所だけです。

UserEmail = User().Email;
UserInfo = LookUp(Users, 'Primary Email' = User().Email);
UserTitle = UserInfo.Title;
UserPhone = Switch(UserInfo.'Preferred Phone', 'Preferred Phone (Users)'.'Mobile Phone', UserInfo.'Mobile Phone',
UserInfo.'Main Phone');

これらの式は計算の本質を体現しています。 これらは、他の値に基づいて UserEmailUserInfoUserTitleUserPhone を決定するプロセスを明確に示しています。 このロジックはカプセル化されており、アプリ全体で広範囲に利用できるほか、単一の場所で変更することもできます。 この適応性は、Dataverse ユーザー テーブルから Office 365 コネクターへの切り替えにも及んでいるため、アプリ全体に散在する計算式を変更する必要はありません。

もうひとつのアプローチは、countRows を最適化することです。

varListItems = CountRows(SampleList)

Set 関数では、変数 varListItems をサンプル リスト内の行の初期数で初期化し、リスト項目が追加または削除された後に再度設定する必要があります。 名前付き数式では、データが変更されると、varListitems 変数が自動的に更新されます。

App.Formulas プロパティ内の名前付き数式は、アプリ全体の値と計算を管理するためのより柔軟で宣言的なアプローチを提供し、 App.OnStartのみに依存する場合と比較して、タイミングの独立性、自動更新、保守性、不変の定義の点で利点があります。

アスペクト 名前付き数式 (App.Formulas) App.OnStart
タイミングの独立性 数式は即座に利用可能で、任意の順序で計算できます。 変数によってタイミングの依存関係が生じ、可用性に影響する可能性があります。
自動更新 依存関係が変更されると、数式が自動的に更新されます。 変数は起動時に一度設定され、手動での更新が必要になる場合があります。
メンテナンス性 数式を 1 か所に集中させることで保守性が向上します。 分散した変数は、複数の場所での検索と更新が必要になる場合があります。
不変的な定義 App.Formulas 内の数式定義は不変です。 変数値は偶発的な変更の影響を受ける可能性があります。

ユーザー定義関数

ユーザー定義関数は、ユーザーが独自のカスタム関数を作成できる Power Apps Authoring Studio の実験的な機能です。

この機能を使用するには、実験設定で新しい分析エンジンとユーザー定義関数 (UDF) を選択します

以下のように App.Formulas で数式を定義します:

FunctionName(Parameter1:DataType1, Parameter2:DataType2):OutputDataType = Formula

コードの動作は次のようになります:

  • FunctionName 関数を呼び出すために使用されます

  • Parameter は入力の名前です。 1 つ以上の入力が可能

  • DataType 関数に渡される引数はこのデータ型と一致する必要があります。 使用可能なデータ型には、ブール値、色、日付、日時、GUID、ハイパーリンク、テキスト、時間、型指定されていないオブジェクトが含まれます

  • OutputDataType は、関数の出力のデータ型です

  • Formula は関数の出力です

// Function to calculate the area of a circle based on the radius
calcAreaOfCircle(radius: Number): Number = 
    IfError(Pi() * radius * radius, 0);

定義された関数内でエラー処理を実装するには、IfError を使用します。

テキスト/ラベル コントロールから定義された関数を呼び出します。

calcAreaOfCircle(Int(*TextInput1*.Text))

注意

この機能は、実験的機能であり、変更される可能性があります。 レコードやフィルターなどの一部のデータ型はまだサポートされていません。

変数を最適化する

変数は、アプリ内のあらゆる場所で使用されるローカル値とグローバル値を定義および設定するために使用されます。 これらは便利ですが、多すぎるとアプリの最適化が低下する可能性があります。

次の例は、オブジェクトの各属性に変数を設定する方法を示しています。この方法では、すべてのプロパティに Set を使用する必要があります。

Set(varEmpName, Office365Users.MyProfile().DisplayName);
Set(varEmpCity, Office365Users.MyProfile().City);
Set(varEmpPhone, Office365Users.MyProfile().BusinessPhones);
Set(varEmpUPN, Office365Users.MyProfile().UserPrincipalName);
Set(varEmpMgrName, Office365Users.ManagerV2(varEmpUPN).DisplayName);

より最適化されたアプローチは、必要なときにプロパティを使用することです:

Set(varEmployee, Office365Users.MyProfile())
"Welcome " & varEmployee.DisplayName

コンテキスト変数とグローバル変数を賢く使用してください。 変数のスコープが 1 つの画面を超えて拡張される場合は、コンテキスト変数ではなくグローバル変数の使用を検討してください。

未使用の変数が多すぎると、メモリ使用量が増加し、アプリの初期化がわずかに遅くなります。 これは、これらの変数がアクティブに使用されていない場合でも、リソースが割り当てられるためです。 未使用の変数が多すぎると、アプリのロジック全体が複雑になる可能性があります。 未使用の変数の影響は深刻ではないかもしれませんが、最適なパフォーマンスと開発のしやすさを確保するために、クリーンかつ整理された Power App を維持することをお勧めします。

コレクションを最適化する

コレクションは一時的なデータストレージ構造で、Power Apps アプリ内でデータを保存したり操作したりするために使用できます。 ただし、コレクションによってパフォーマンスのオーバーヘッドが発生する可能性があるかどうかについては微妙な問題があります。 したがって、コレクションの使用を制限してください。 必要なときだけ使用するようにしてください。

// Use this pattern
ClearCollect(colErrors, {Text: gblErrorText, Code: gblErrorCode});

// Do not use this pattern
Clear(colErrors);
Collect(colErrors, {Text: gblErrorText, Code: gblErrorCode});

ローカル コレクションのレコードを数えるには、Count(Filter()) の代わりに CountIf を使用します。

コレクションを操作するときは、次のガイダンスを考慮してください:

コレクションのサイズと数を制限します。 コレクションはアプリに対してローカルであるため、モバイル デバイスのメモリに保存されます。 コレクションが保持するデータが増えるほど、またはコレクションの数が増えるほど、パフォーマンスは低下します。 特定の列のみを取得するには、ShowColumns 関数を使用します。 関連するデータのみを取得するには、Filter 関数を追加します。

次のサンプル関数は、データセット全体を返します。

ClearCollect(colDemoAccount, Accounts);

特定のレコードと列のみを返す以下のコードと比較してください:

ClearCollect(colAcc,
              ShowColumns(
                Filter(Accounts, !IsBlank('Address 1: City')),
                "name","address1_city"))

たとえば、このコードはこのデータセットを返します:

colAcc というテーブルと、address1_city と name という 2 つのデータ列を持つデータセットのスクリーンショット

データソースの更新頻度の設定。 コレクションに新しいレコードを追加する場合は、コレクションを更新するか、コレクションに収集して、新しいレコードまたは変更されたレコードを取得する必要があります。 データ ソースが複数のユーザーによって更新された場合、新しいレコードまたは変更されたレコードを取得するにはコレクションを更新する必要があります。 更新呼び出しが増えると、サーバーとのやり取りも増えます。

コレクションと変数にデータをキャッシュする

コレクションは、本質的にはテーブル変数であり、単一のデータ項目ではなく、データの行と列を格納するという点で異なります。 その有用性は主に 2 つの目的にあります: 1 つ目は、データソースに送信する前にデータを集約すること、2 つ目は、情報をキャッシュすることで、データソースへの頻繁な問い合わせを不要にすることです。 コレクションはデータソースと Power Apps の両方の表形式構造と整合しているため、オフラインのシナリオでもデータを効率的に操作できます。

// Clear the contents of EmployeeCollection, it already contains data
ClearCollect(
    colEmployee,
    {
        Id: "1",
        Name: "John",
        Department: "IT"
    },
    {
        Id: "2",
        Name: "Nestor",
        Department: "IT"
    }
)

未使用の変数とメディアを削除する

未使用のメディアや変数はアプリのパフォーマンスに大きな影響を与えない可能性もありますが、未使用のメディアや変数をアプリからクリーンアップすることが重要です。

  • 未使用のメディア ファイルは、アプリ全体のサイズの増加につながります。 これにより、アプリの読み込み時間が遅くなる可能性があります。

  • 未使用の変数はメモリ使用量を増加させ、アプリの初期化がわずかに遅くなります。 これは、これらの変数がアクティブに使用されていない場合でも、リソースが割り当てられるためです。 さらに、未使用の変数が多すぎると、アプリのロジックが全体的に複雑になります。

  • App Checker を使用して、未使用のメディアと変数を確認します。

画面とコントロールを最適化する

相互参照コントロールを避ける

他の画面上のコントロールを参照するコントロールにより、アプリの読み込みとナビゲーションが遅くなる可能性があります。 こうすることで、ユーザーがその画面に移動するまで待つのではなく、アプリが他の画面をすぐにロードするようになります。 この問題に対処するには、代わりに変数、コレクション、ナビゲーション コンテキストを使用して、画面間で状態を共有します。

作成スタジオの Power Apps App チェッカーでは、相互参照されているコントロールが表示されます。 この問題に対処するには、App チェッカーを定期的に確認してください。

相互参照コントロールの例を次に示します。 下の画像では、ギャラリー 1 のコントロールが、画面 2 のラベル 2 のコントロールで相互参照されています。

相互参照コントロールを示す Power Apps Studio のスクリーンショット

アプリの最初の画面のコントロールを 2 番目の画面で参照する場合、最初の画面はすでにロードされているため、パフォーマンスへの影響はありません。これは、変数を使用する代わりにアプリが宣言的であるため、実際には良いことかもしれません。

まだロードされていないコントロールを参照する場合、例えば最初の画面で画面 3 から Label 3 という名前のコントロールを参照する場合、その画面をメモリにロードする必要があります。

テキスト コントロールの DelayOutput を有効にします

ディレイ出力設定 true に設定すると、ユーザー入力は半秒遅れて登録されます。 負荷のかかる操作をユーザーがテキストの入力を完了するまで遅らせる場合 (つまり、入力が他の数式で使用される際にフィルタ処理する場合) に便利です。

たとえば、TextInput コントロールに入力された内容に応じてアイテムがフィルターされるギャラリーの場合:

  • DelayOutput を false (既定) に設定すると、テキストが入力されるとすぐにギャラリーがフィルタリングされます。 ギャラリーに多数のアイテムがある場合、変更を加えてすぐにギャラリーを再読み込みするとパフォーマンスが低下するため、少し待機する方が有利です。 これは、検索文字列に TextInput を使用する場合に便利です (検索 または新しい StartsWith 関数)。

  • DelayOutput を true に設定すると、変更が検出されるまでに 1 秒の遅延が発生します。 これは、必要な入力を完了するための時間を与えるために行われます。 遅延は、TextInput.OnChange プロパティを補助するために使用するとうまく機能します。 変更に関連付けられたアクションがある場合、必要なものがすべてフィールドに入力されるまで、それらのアクションはトリガーされません。

委任とサーバー側処理

委任

Power Apps における委任とは、アプリが Power Apps 自身の中で操作を処理するのではなく、基礎となるデータソースに特定の操作をオフロードする能力を指す概念です。 委任を使用することで Power Apps 開発者は、大規模なデータセットを扱うシナリオでも優れたパフォーマンスを発揮する、より効率的でスケーラブルなアプリケーションを作成できます。 特定のデータ ソースと操作の委任制限を認識し、それに応じてアプリを設計して最適なパフォーマンスを実現することが重要です。

![注意] すべての機能が委任できるわけではありません。 委任の詳細については、委任を理解するをご参照ください。

委任には、クエリの最適化や大規模なデータセットのサポートの追加など、いくつかの利点があります。 さらに、ソース データが頻繁に変更される場合、委任によってデータを最新の状態に保つことができます。

データ ソース への API 呼び出しを削減する

場合によっては、キャンバス アプリ内で結合を実行してコレクションを作成するなどのコーディング手法に従うだけで便利なことがあります。 以下のコードを参照してください:

この例では、Drivers と Trucks という 2 つのテーブルがあります。 開発者は、ドライバーとトラックの詳細のコレクションを作成するコードを作成し、各トラックごとに、トラックを所有するドライバーを呼び出します。

// Bad code
ClearCollect(vartruckdata, AddColumns('Truck Details',
    "CITY",LookUp(Drivers, 'Truck Details'\[@'Dummy ID'\] = Drivers\[@'Truck Details'\],City),
        "FIRSTNAME",LookUp(Drivers, 'Truck Details'\[@'Dummy ID'\] = Drivers\[@'Truck Details'\],'Driver First Name'),
    "LASTNAME",LookUp(Drivers, 'Truck Details'\[@'Dummy ID'\] = Drivers\[@'Truck Details'\],'Driver Last Name'),
        "STATE",LookUp(Drivers, 'Truck Details'\[@'Dummy ID'\] = Drivers\[@'Truck Details'\],State)));

キャンバス アプリ内からこのような結合操作を実行すると、データ ソース への呼び出しが多数生成され、読み込み時間が非常に遅くなる可能性があります。

より良いアプローチは次のとおりです:

// Good code
Set(
    varTruckData,
    LookUp(
        Drivers,
        'Dummy ID' = ThisRecord.'Dummy ID',
        'Driver First Name'
    ) & LookUp(
        Drivers,
        'Dummy ID' = ThisRecord.'Dummy ID',
        'Driver Last Name'
        )
);

Set(
    varTruckData,
    With(
        {
            vDriver: LookUp(
                Drivers,
                'Dummy ID' = ThisRecord.'Dummy ID'
            )
        },
        vDriver.'Driver First Name' & vDriver.'Driver Last Name'
    )
)

リアルタイムのシナリオでは、データ ソース レベルでデータを修正するだけで、読み込み時間を 5 分から 10 秒未満に短縮できます。

サーバー側の処理

SQL や Dataverse などのさまざまなデータソースでは、フィルターやルックアップなどのデータ処理をデータソースに委譲することができます。 SQL Server では、ユーザーはクエリによって定義されたコンテンツを持つビューを作成できます。 同様に、Dataverse を使用すると、ユーザーはローコード プラグインを作成してサーバー側でデータ処理のロジックを記述し、キャンバス アプリで最終結果のみを取得できます。

データ処理をサーバーに委任すると、全体的なパフォーマンスが向上し、クライアント側のコードが削減され、保守が容易になります。

Dataverse のプラグインの詳細情報。

クエリ データ パターンの最適化

明示的な列の選択を使用する

明示的な列の選択 (ECS) 機能は、すべての新しいアプリで既定で有効になっています。 アプリ用に有効になっていない場合は、有効にする必要があります。 ECS は、取得される列の数を自動的にアプリケーションで使用される列のみに減らします。 ECS が有効になっていない場合、必要以上のデータを取得し、パフォーマンスに影響を与える可能性があります。 場合によっては、アプリがコレクションを通じてデータをプルするとき、列の元の系統やソースが失われることがあります。 使用されているかどうかは分からないので、ECS を使用してドロップします。 通常、コレクション参照の後に PowerFx 式 ShowColumns を使用するか、コントロール内で使用することで、欠落列に対して ECS を強制的に動作させることができます。

コレクションにデータを入力するには Power Automate を呼び出すことを回避する

一般的なプラクティスは、Power Automate を使用して Power Apps のコレクションを取得し、入力することです。 このアプローチは有効ですが、最も効率的な選択ではない状況もあります。 Power Automate の呼び出しにはネットワーク遅延のオーバーヘッドが発生し、Power Automate フローをインスタンス化するために 0.6 秒のパフォーマンスコストが追加されます。

Power Automate フローの過剰使用は、実行制限やスロットリングにもつながります。 したがって、ネットワーク遅延とパフォーマンスコストのトレードオフを常に評価してください。

N+1 問題を解消する

N+1 問題は、データベース クエリでよく発生する問題で、1 回のクエリで必要なデータをすべて取得するのではなく、関連するデータを取得するために複数の追加クエリが実行されます。 追加のクエリごとにオーバーヘッドが発生するため、パフォーマンスの問題が発生する可能性があります。

コレクションをロードするためのこのような単純な呼び出しにより、データ ソース への N+1 回の呼び出しが生成される場合があります。

ClearCollect(MyCollection, OrdersList,
    {
        LookUp(CustomersList,CustomerID = OrdersList[@CustomerID])
    }
)

キャンバス アプリとギャラリーのコンテキストでは、関連レコードを表示するデータ ソースとギャラリーを操作するときに、N+1 問題が発生する可能性があります。 この問題は通常、ギャラリーに表示される各アイテムに対してより多くのクエリが実行され、パフォーマンスのボトルネックが発生する場合に発生します。

N+1 クエリの問題を回避するには、SQL Server の View オブジェクトを使用するか、ユーザー インターフェイスを変更して N+1 シナリオのトリガーを回避します。

Dataverse は自動的に関連テーブルの必要なデータを取得し、関連テーブルから列を選択することができます。

ThisItem.Account.'Account Name'

RelatedDataSourc のサイズが小さい場合 (<500レコード)、コレクションにキャッシュし、Lookup (N+1) クエリのシナリオを実行するためにコレクションを使用することができます。

パッケージサイズの制限

Power Apps はアプリの読み込みを最適化するために多くのことを行いますが、アプリのフットプリントを削減するための手順を実行できます。 フットプリントの削減は、古いデバイスのユーザーや、レイテンシが高かったり帯域幅が狭かったりする地域のユーザーにとって特に重要です。

  • アプリに埋め込まれているメディアを評価します。 使用されていないものは削除します。

  • 埋め込まれた画像が大きすぎる可能性があります。 PNG ファイルの代わりに、SVG 画像を使用できるかどうかを確認します。 ただし、SVG 画像でテキストを使用する場合は、使用するフォントをクライアントにインストールする必要があるため、注意が必要です。 テキストを表示する必要がある場合の優れた回避策は、画像の上にテキスト ラベルを重ねることです。

  • 解像度がフォーム ファクターに適切かどうかを評価します。 モバイル アプリの解像度は、デスクトップ アプリの解像度ほど高くする必要はありません。 画像の品質とサイズの適切なバランスが得られるように試行錯誤が必要となります。

  • 使用していない画面がある場合は削除してください。 アプリ作成者または管理者のみが使用する非表示の画面を削除しないように注意してください。

  • 1 つのアプリにあまりにも多くのワークフローを詰め込もうとしていないかどうかを評価します。 たとえば、同じアプリに管理画面とクライアント画面の両方がありますか? その場合は、個別のアプリに分割することを検討してください。 このアプローチにより、複数の人が同時にアプリで作業することが容易になり、アプリの変更に完全なテストパスが必要な場合の「爆発半​​径」 (テストの量) が抑制されます。

すべてに最適化

Power Apps の ForAll 関数は、レコードのテーブルを繰り返し処理し、各レコードに数式を適用するために使用されます。 関数自体は多用途ですが、ForAll 関数を不適切に使用すると、アプリのパフォーマンスが急速に低下する可能性があります。

ForAll 関数は並行関数ではなく、単一の順次関数です。 したがって、一度に 1 つのレコードのみを調べて結果を取得し、その範囲内のすべてのレコードを調べるまで次のレコードに進みます。

ForAll のネスト化は絶対に避けてください。 これにより指数関数的な反復が発生し、パフォーマンスに大きな影響を与える可能性があります。

ClearCollect(FollowUpMeetingAttendees.ForAll(ForAll(Distinct(AttendeesList.EmailAddress.Address).Lookup(Attendees))))

データベースへのバッチ更新

ForAll + Patch は、データベースをバッチ更新する 1 つの方法です。 ただし、For All と Patch の順序には注意してください。

次の機能:

Patch(SampleFoodSalesData, ForAll(colSampleFoodSales,
    {
        demoName:"fromCanvas2"
    })
);

次よりも優れたパフォーマンスを発揮します:

ForAll(colSampleFoodSales, Patch(SampleFoodSalesData,
    {
        demoName:"test"
    })
);

次のステップ