次の方法で共有


コードの最適化

キャンバス アプリがさまざまなビジネス ニーズを満たすために進化するにつれて、パフォーマンスを最適に保つことが重要です。 データ処理、ユーザー インターフェイスの設計、アプリの機能のすべてにおいて、コードの最適化には慎重なアプローチが必要です。

キャンバス アプリが複雑になると、データの取得、数式の複雑さ、レンダリング速度に関する問題が発生する可能性があります。 強力な機能と応答性の高いユーザー インターフェイスのバランスを取るために、コードの最適化に体系的なアプローチを使用します。

Power Fx 数式の最適化

このセクションでは、Power Fx 数式を最適化するためのベスト プラクティスについて説明します。

関数付き

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

With 関数を使用する Power Fx 数式のスクリーンショット。

並行関数

Concurrent関数を使用すると、コネクタまたは Dataverse 呼び出しがある場合に、同じプロパティ内の複数の数式を同時に評価できます。 通常、; (セミコロン) 演算子で連結すると、複数の数式が同時に評価されます。 Concurrent を使用すると、; 演算子を使用した後でも、アプリはプロパティ内のすべての数式を同時に評価します。 このコンカレンシーは、ユーザーが結果を待つ時間が短くなることを意味します。 前の呼び出しが完了するまで、データ呼び出しが開始されない場合、アプリはすべての要求時間の合計を待機する必要があります。 データ呼び出しが同時に開始された場合、アプリは最も長いリクエスト時間だけ待機します。 同時実行関数の詳細を確認します。

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

Coalesce 関数

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

この例では、 value1value2 を 2 回評価する必要があります。

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

この関数は次のように簡略化できます:

Coalesce(value1, value2)

IsMatch 関数

IsMatch 関数は、テキスト文字列が通常の文字、定義済みのパターン、または正規表現で構成されるパターンに一致するかどうかをテストします。 IsMatch 関数の詳細を確認します。

たとえば、次の数式は、United States社会保障番号と一致します。

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 関数を効率化します。 名前付き数式 (特にアプリのライフサイクルの早い段階で構成されたもの) は有利です。 これらの数式は、データ呼び出しに基づいて変数の初期化を処理し、コードに、よりクリーンで整理された構造を提供します。 詳細については、 大規模で複雑なキャンバス アプリの構築に関するページを参照してください。

注意

OnStart プロパティは必須です。 これは、最初の画面が表示される前に実行する必要がある作業の順序付けされた一覧です。 何を行う必要 があるか だけでなく、順序に基づいて作業を行う必要がある 場合 にも非常に具体的であるため、それ以外の場合に行われる可能性のある並べ替えと遅延の最適化が制限されます。

開始画面

App.OnStart Navigate関数呼び出しが含まれている場合、If関数内にあり、ほとんど呼び出されない場合でも、アプリはアプリの最初の画面を表示する前にApp.OnStartの実行を完了する必要があります。  App.StartScreen は、どの画面を最初に表示するかを示す宣言型の方法であり、最適化をブロックしません。

StartScreen プロパティを設定すると、App.OnStart が完了する前に最初の画面が表示されます。 App.StartScreen は、前処理を必要とせずに最初に表示する画面オブジェクトを宣言します。

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

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)

詳細情報: App.StartScreen: App.OnStart での Navigate の宣言型の代替手段

警告

StartScreenOnStart の依存関係を避けてください。 グローバル変数を参照する名前付き数式を参照すると、 StartScreen が正しく適用されない競合状態が発生する可能性があります。

StartScreenOnStartの間に依存関係を作成しないでください。 アプリは 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";

別の例として、 Lookupsの設定があります。 ここでは、Dataverse ではなくOffice 365からユーザー情報を取得するために、Lookup 数式で変更が必要です。 すべての場所でコードを変更することなく、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 Users テーブルから Office 365 コネクタに切り替えるまで拡張され、アプリ全体に散在する数式を変更する必要はありません。

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

varListItems = CountRows(SampleList)

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

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

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

ユーザー定義関数

Power Apps Studio のユーザー定義関数独自のカスタム関数を作成できます。

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

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

コードは次のように動作します。

  • FunctionName は関数を呼び出します。

  • Parameter は入力の名前です。 1 つ以上の入力を含めることができます。

  • DataType は、関数に渡される引数が一致する必要があるデータ型です。 使用できるデータ型は、ブール値、色、日付、Datetime、動的、GUID、ハイパーリンク、テキスト、時刻です。

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

  • Formula は関数の出力です。

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

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

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

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 アプリにデータを格納および操作するために使用する一時的なデータstorage構造です。 ただし、コレクションによってパフォーマンスのオーバーヘッドが発生する可能性があります。 コレクションの使用を制限し、必要な場合にのみ使用してください。

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

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

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

コレクションを使用する場合は、次の方法を検討してください。

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

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

    ClearCollect(colDemoAccount, Accounts);
    

    この関数を、特定のレコードと列のみを返す次のコードと比較します。

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

    この例では、次のデータセットが返されます。

    colAcc という名前のテーブルと、address1_cityと名前の 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で画面とコントロールを最適化するには、次のベスト プラクティスを検討してください。

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

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

Power Apps Studio のアプリ チェッカーには、相互参照されているコントロールが表示されます。 この問題を解決するには、アプリ チェッカーを定期的に確認してください。

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

Power Apps Studio のスクリーンショットには、クロスリファレンスのコントロールを示しています。

アプリ内で2番目の画面から最初の画面のコントロールを参照しても、最初の画面は既に読み込まれているため、パフォーマンスに影響を与えません。 この動作は、アプリが変数を使用する代わりに宣言型であるため、実際には有益です。

まだ読み込まれていないコントロール (画面 3 から Label 3 という名前のコントロールを参照する最初の画面など) を参照すると、アプリはその画面をメモリに読み込みます。

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

DelayOutput 設定を true に設定すると、5 分の 1 の遅延後にユーザー入力が登録されます。 この遅延は、他の数式で入力を使用する場合のフィルター処理など、ユーザーがテキストの入力を完了するまでコストのかかる操作を延期する場合に便利です。

たとえば、TextInput コントロールにユーザーが入力した内容に応じて アイテム がフィルター処理されるギャラリーを考えてみます。

  • DelayOutput を false (既定値) に設定すると、任意のテキストが入力されるとすぐにギャラリーがフィルター処理されます。 多数の項目を含むギャラリーがある場合、すぐに変更を加えてギャラリーを再読み込みすると、パフォーマンスが低下します。 待つ方が良いです。 この動作は、検索文字列またはTextInput関数にStartsWithを使用している場合に実用的です。

  • DelayOutput を true に設定すると、変更が検出されるまでに短い遅延が発生します。 この遅延により、入力を完了する時間が提供されます。 遅延は、 TextInput.OnChange プロパティで適切に機能します。 変更に関連付けられているアクションがある場合は、フィールドへの入力が完了するまでトリガーされないようにします。

委任とサーバー側の処理

委任とサーバー側の処理を使用すると、データ ソースに操作をオフロードすることで、アプリで大規模なデータセットを効率的に処理できます。

権限委譲

Power Appsでの委任とは、Power Apps自体で操作を処理するのではなく、基になるデータ ソースに特定の操作をオフロードするアプリの機能を指します。 Power Appsで委任を使用することで、大規模なデータセットを含むシナリオでも優れたパフォーマンスを発揮する、より効率的でスケーラブルなアプリケーションを作成できます。 特定のデータ ソースと操作の委任の制限に注意し、最適なパフォーマンスを実現するようにアプリを設計します。

注意

すべての関数が委任できるわけではありません。 委任の詳細については、「 クエリの制限事項: 委任とクエリの制限」を参照してください。

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

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

場合によっては、キャンバス アプリ内で結合を実行してコレクションを作成すると便利な場合があります。 下記の例を検討してください。 この例には、ドライバーとトラックの 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 は、使用されていることを判断できない場合は列を削除します。 ECS に不足している列を強制的に保持するには、コレクション参照の後、またはコントロールで ShowColumns Power Fx 式を使用します。

Power Automateを呼び出してコレクションを設定しないようにする

一般的な方法として、Power Automateを使用してPower Appsのコレクションを取得して設定することがあります。 このアプローチは有効ですが、最も効率的な選択ではない状況もあります。 Power Automateを呼び出すと、ネットワーク待機時間と 0.6 秒のパフォーマンス コストが追加され、Power Automate フローがインスタンス化されます。

Power Automate フローの過剰使用は、実行の制限とスロットリングにつながる可能性もあります。 ネットワーク待機時間とパフォーマンス コストの間のトレードオフを常に評価します。

N+1 問題を解消する

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

コレクションを読み込む単純な呼び出しでは、データ ソースへの N+ 1 呼び出しを生成できます。

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

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

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

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

ThisItem.Account.'Account Name'

RelatedDataSourceサイズが小さい (レコード数が 500 未満) 場合は、コレクションにキャッシュし、コレクションを使用してルックアップ (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))))

データベースをバッチ更新する

ForAllPatchを使用して、データベースをバッチ更新できます。 ただし、 ForAllPatchの順序を使用するときは注意してください。

次の関数は、次のようなより優れたアプローチです。

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

一方、次のアプローチは効率が低くなります。

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

次のステップ