次の方法で共有


コードの最適化

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

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

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 のユーザー定義関数を使用すると、ユーザーは独自のカスタム関数を作成できます。

この機能を使用するには、プレビュー設定でユーザー定義関数 (UDFs) をオンにします。 プレビュー機能は運用環境では使用すべきではないため、既定では無効になっていますが、まもなく一般提供される予定です。

以下のように 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});

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

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

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

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

ClearCollect(colDemoAccount, Accounts);

これを、特定のレコードと列のみを返す次のコードと比較してください。

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

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

colAcc という名前のテーブルと、address1_city と name の 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 Studio の App チェッカーは、相互参照されているコントロールを表示します。 この問題を解決するには、アプリ チェッカーを定期的に確認してください。

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

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

アプリの最初の画面のコントロールを 2 番目の画面で参照する場合、最初の画面は既に読み込まれているため、パフォーマンスへの影響はありません。 アプリは変数を使用するのではなく宣言型であるため、これは実際には良いことです。

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

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

DelayOutput 設定を true に設定すると、0.5 秒の遅延の後、ユーザー入力が登録されます。 これは、入力が他の数式で使用されている場合のフィルター処理など、ユーザーがテキスト入力を終えるまで負荷のかかる処理を遅延させる際に便利です。

たとえば、ユーザーが TextInput コントロールに入力した内容に応じて Items がフィルター処理される Gallery の場合、次のようになります。

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

  • DelayOutput を true に設定すると、変更が検出されるまでに短い遅延が発生します。 これにより、入力を終了する時間が与えられます。 この遅延は、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 は、列が使用されていることを認識できない場合、列を削除します。 ECS が欠落している列を強制的に保持するには、コレクション参照の後またはコントロール内で PowerFx の式 ShowColumns を使用します。

コレクションにデータを入力するには 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"
    })
);

次のステップ