次の方法で共有


Fabric Graph で GQL クエリのパフォーマンスを最適化する

現在、この機能はパブリック プレビュー段階にあります。 このプレビュー版はサービス レベル アグリーメントなしで提供されています。運用環境のワークロードに使用することはお勧めできません。 特定の機能はサポート対象ではなく、機能が制限されることがあります。 詳細については、「 Microsoft Azure プレビューの使用条件を参照してください。

この記事では、Fabric Graph を使用するときに予測可能かつ効率的に実行される GQL (Graph クエリ言語) クエリを記述するためのガイダンスを提供します。 推奨事項は、現在のプラットフォームの動作と文書化された制約に基づいています。

グラフサイズ、結果サイズ、およびクエリタイムアウトのハード制限については、「 現在の制限事項」を参照してください。

パターンの早い段階でフィルター処理する

後のステートメントではなく、グラフ パターン内にフィルターを配置します。 パターン レベルの WHERE 句を使用すると、結合および後続のステートメントを実行する前の中間結果の数が減り、全体的な実行コストが削減されます。

推奨: パターン マッチング中にフィルターを適用します。

-- Pattern-level WHERE reduces intermediate results
MATCH (p:Person WHERE p.birthday < 19940101)-[:workAt]->(c:Company WHERE c.id > 1000)
RETURN p.firstName, p.lastName, c.name

避ける: 別の FILTER ステートメントでフィルターを遅れて適用すること。

-- Statement-level filter runs after all pattern matches are produced
MATCH (p:Person)-[:workAt]->(c:Company)
FILTER p.birthday < 19940101 AND c.id > 1000
RETURN p.firstName, p.lastName, c.name

どちらのクエリも同じ結果を返しますが、最初のバージョンでは、クエリ エンジンが評価プロセスの前の行を排除できます。

ヒント

パターン レベルの WHERE は、SQL JOIN ... ON 条件に似ています。 結果セット全体をフィルター処理するのではなく、評価の時点で一致を制限します。

必要なプロパティのみを返します

シナリオで必要なノードとエッジのプロパティのみを返します。 プロパティのサブセットのみが必要な場合は、完全なノードを返したり、 RETURN * を使用したりしないでください。

Graph では、OneLake テーブルはノードのプロパティを返します。 不要なプロパティを選択すると、データの読み取り、シリアル化コスト、応答サイズが増加します。 グラフ モデリング中、ソース テーブルのすべての列は、削除しない限り、既定でプロパティとして追加されます。

推奨: 狭い投影。

MATCH (p:Person)-[:workAt]->(c:Company)
RETURN p.firstName, p.lastName, c.name

避ける: 完全なノードを返します。

MATCH (p:Person)-[:workAt]->(c:Company)
RETURN *

各プロパティの横にあるごみ箱アイコンを選択して、グラフ モデリング中に未使用のプロパティを削除します。 ノードあたりのプロパティ数が少ないほど、storageとクエリのオーバーヘッドの両方が削減されます。

結果セットのサイズを制限する

カーディナリティが高いノードまたはリレーションシップに対してクエリを実行する場合は、 LIMIT またはその他の境界条件を適用します。 無制限のグラフの一致により、プラットフォームの制限に近づく非常に大きな結果セットが生成される可能性があります。

推奨: 境界付き結果。

MATCH (p:Person)-[:knows]->(friend:Person)
RETURN p.firstName, friend.firstName
LIMIT 1000

避ける: 制約のない高カーディナリティのマッチ。

MATCH (p:Person)-[:knows]->(friend:Person)
RETURN p.firstName, friend.firstName

Important

グラフでは、64 MB を超える応答が切り捨てられ、結果が 128 MB を超えると集計のパフォーマンスが不安定になる可能性があります。 FILTERLIMIT、およびGROUP BYを使用して、これらの範囲内に結果を保持します。 詳細については、現在の制限事項に関する記事を参照してください。

トラバーサルを浅くし、目標に合わせて行う

深く入れ子になったグラフ パターンや複雑なグラフ パターンは避けてください。 特定の質問に直接答える単純なターゲット トラバーサルを優先します。 可変長パターンの各余分なホップは、特に密に接続されたグラフで、エンジンが評価するパスの数を指数関数的に増加させることができます。

推奨: 厳密な制限。

-- Use the narrowest hop range that answers your question
MATCH (p:Person)-[:knows]->{1,3}(friend:Person)
RETURN p.firstName, friend.firstName
LIMIT 1000

避ける: 明確な必要がない場合の最大深度トラバーサル。

-- Exploring the full 8-hop limit on a dense graph is expensive
MATCH (p:Person)-[:knows]->{1,8}(friend:Person)
RETURN *

Important

Graph では、可変長パターンで最大 8 ホップ がサポートされます。 それでも、シナリオで許容される最も厳しい境界を使用します。 この例では、 {1,3} パターンは、同じグラフ上の {1,8} よりも大幅に安価です。

TRAIL を使用して冗長トラバーサルを防ぐ

TRAILパス モードを使用して、クエリ エンジンが同じエッジを再訪しないようにします。 密度の高いグラフでは、サイクルによって指数関数的なパスの爆発が発生する可能性があります。 TRAIL は、各エッジがパスごとに最大 1 回アクセスされることを保証するため、正確性とパフォーマンスの両方が向上します。

-- TRAIL prevents revisiting the same :knows edge
MATCH TRAIL (src:Person)-[:knows]->{1,4}(dst:Person)
WHERE src.firstName = 'Alice' AND dst.firstName = 'Bob'
RETURN count(*) AS numPaths

TRAILしないと、循環グラフに対して同じクエリを実行すると、はるかに大きな (多くの場合冗長な) 結果セットが生成される可能性があります。

効率的な結合に共有変数を使用する

クエリで複数のリレーションシップのデータが必要な場合は、共有変数を使用して同じエンティティのパターンを結合します。 共有変数がない場合、パターンはデカルト積 (両方のパターンからの一致のすべての組み合わせ) を生成でき、結果セットが大幅に大きくなります。

推奨: 共有変数 p パターンを結合します。

-- Single shared variable ensures an efficient join
MATCH (p:Person)-[:workAt]->(c:Company),
      (p)-[:isLocatedIn]->(city:City)
RETURN p.firstName, c.name AS company, city.name AS city
LIMIT 1000

避ける: 共有変数のない独立したパターン。

-- Without a shared variable, this produces a cartesian product
MATCH (p1:Person)-[:workAt]->(c:Company),
      (p2:Person)-[:isLocatedIn]->(city:City)
RETURN p1.firstName, c.name, p2.firstName, city.name

デカルト積は、1 つのパターンのすべての結果と、もう一方のパターンのすべての結果をペアにしています。 Person-workAt->Companyが 1,000 行に一致し、Person-isLocatedIn->Cityが 500 行に一致する場合、クエリは 1,000 × 500 = 500,000 行を返します。 共有変数を追加すると結合が制約されるため、一致するペアのみが返されます。

ノードのキー制約を定義する

グラフの種類で ノード キー制約 を定義します。 キー制約により、システムは、リレーショナル データベースの主キー インデックスと同様に、キー プロパティによって特定のノードを検索するクエリを最適化できます。

たとえば、グラフの種類で、id ノードのキーとしてPersonが定義されている場合は、次のようになります。

CONSTRAINT person_pk
  FOR (n:Person) REQUIRE n.id IS KEY

その後、 id でフィルター処理するクエリでは、そのキーを直接参照に使用できます。

-- Fast: the engine can look up person 12345 directly using the key
MATCH (p:Person WHERE p.id = 12345)-[:workAt]->(c:Company)
RETURN p.firstName, c.name

キー プロパティのフィルターを使用しない場合、エンジンはすべての Person ノードをスキャンする必要があります。

-- Slower: scans all Person nodes before traversing
MATCH (p:Person)-[:workAt]->(c:Company)
RETURN p.firstName, c.name

ヒント

特定のノードが必要な場合は、定義した制約を利用するために、 MATCH パターンでそのキー プロパティをフィルター処理します。

適切なデータ型を選択する

グラフ モデリング中に、プロパティごとに最も具体的なデータ型を選択します。 適切な型を選択することは、storageの効率とクエリのパフォーマンスの両方にとって重要です。 たとえば、 INT プロパティの数値比較は、同等の STRING 値での文字列比較よりも高速です。

サポートされているデータ型については、「 現在の制限事項 - データ型サポートされるプロパティ型」を参照してください。

可能であれば、同じエッジを個別に走査する個別のクエリを発行するのではなく、1 つのグラフ パターンで関連エンティティを取得します。 トラバーサルを組み合わせると、冗長なパターン マッチングが回避され、N+1 クエリの問題が回避されます。最初の 1 つのクエリによって、結果行ごとに個別のクエリがトリガーされます。

推奨: 単一の結合パターン。

MATCH (c:Customer)-[:purchased]->(o:Order)-[:contains]->(product:Product)
RETURN c.id, o.id, product.name
LIMIT 1000

避ける: 同じ Customer → Order エッジを走査する 2 つの個別のクエリ。

-- Query 1: fetch 100 orders
MATCH (c:Customer)-[:purchased]->(o:Order)
RETURN c.id, o.id

-- Query 2: run once per order to get products (N+1 problem)
MATCH (o:Order)-[:contains]->(product:Product)
RETURN o.id, product.name

現実的なデータ ボリュームに対してクエリをテストする

小さなデータセットに対して適切に実行されるクエリは、直線的にスケーリングされない可能性があります。 予想される運用ワークロードを表すデータ ボリュームを使用してクエリをテストします。

  • フィルターと制限を含む保守的なクエリ図形を使用します。
  • 大規模なグラフに対する探索的な "すべてを返す" クエリは避けてください。
  • 20 分間のタイムアウト制限に対するクエリ期間を監視します。