18.12 PGQL問合せをチューニングするためのベスト・プラクティス

このセクションでは、メモリー割当て、並列度および問合せ計画に関するベスト・プラクティスについて説明します。

18.12.1 メモリー割当て

グラフ・サーバー(PGX)にはon-heapおよびoff-heapメモリーがあり、前者は標準JVMヒープですが、後者はPGXによって管理される別のヒープです。グラフ・データと同様に、PGQL問合せの中間結果および最終結果は、一部がオンヒープおよび一部がオフヒープで格納されます。したがって、両方のヒープが必要です。

オンヒープ・メモリーの場合、JVMの起動時にデフォルトの最大値が選択されますが、-Xmxオプションを介して上書きできます。

オフヒープの場合、デフォルトでは最大値は設定されず、オフヒープのメモリー使用量はシステム・リソースを使い果たすまで自動的に増加し続けます。システム・リソースがなくなると、操作が取り消され、メモリーが解放され、適切な例外がユーザーに渡されます。必要に応じて、グラフ・サーバー(PGX)のmax_off_heap_sizeオプションを介して最大オフヒープ・サイズを構成できます。

可能なかぎり最大のグラフをロードして問合せを実行できるようにするための適切な開始点として、オンヒープ・とオフヒープの比率を1対1にすることをお薦めします。オンヒープ・メモリー・サイズを構成するステップは、「オンヒープ制限の構成」を参照してください。

18.12.2 並列度

デフォルトでは、使用可能なすべてのプロセッサ・スレッドがPGQL問合せの処理に使用されます。ただし、必要に応じてグラフ・サーバー(PGX)のparallelismオプションを設定することにより、スレッドの数を制限できます。

グラフ・サーバーの構成パラメータの詳細は、グラフ・サーバー(PGX)エンジンの構成パラメータを参照してください。

18.12.3 問合せ計画の説明

PgxGraph.explainPgql(String query)メソッドは、問合せの問合せ計画を把握するために使用されます。このメソッドは、次のメソッドを持つOperation (package oracle.pgx.api)のインスタンスを返します。

  • print(): 操作とその子操作を出力するため
  • getOperationType(): 操作のタイプを取得するため
  • getPatternInfo(): 操作の文字列表現を取得するため
  • getCostEstimate(): 操作のコストを取得するため
  • getTotalCostEstimate(): 操作とその子操作のコストを取得するため
  • getCardinatlityEstimate(): 予想される結果行数を取得するため
  • getChildren(): 子操作にアクセスするため

次のケースについて検討します。

g.explainPgql("SELECT COUNT(*) FROM MATCH (n) -[e1]-> (m) -[e2]-> (o)").print()
\--- GROUP BY  GroupBy {"cardinality":"42", "cost":"42", "accumulatedCost":"58.1"}
     \--- (m) -[e2]-> (o) NeighborMatch {"cardinality":"3.12", "cost":"3.12", "accumulatedCost":"16.1"}
          \--- (n) -[e1]-> (m) NeighborMatch {"cardinality":"5", "cost":"5", "accumulatedCost":"13"}
               \--- (n) RootVertexMatch {"cardinality":"8", "cost":"8", "accumulatedCost":"8"}

前述の例では、print()メソッドを使用して問合せ計画を出力しています。

問合せ計画が最適でない場合、パフォーマンスを向上させるために問合せを書き直せることがよくあります。たとえば、合計実行時間を改善する方法として、SELECT問合せをUPDATEおよびSELECT問合せに分割できます。

グラフ・サーバー(PGX)はヒント・メカニズムを提供していないことに注意してください。

また、問合せ計画を出力すると、問合せで使用されているフィルタが表示されます。たとえば:

g.explainPgql("SELECT id(n) FROM MATCH (n)-[e]->(m) WHERE " +
...> "id(n) > 500 " +
...> "AND id(n) < 510 " +
...> "AND id(n) <> 509 " +
...> "AND id(n) <> 507 ").print()
\--- Projection {"cardinality":"146", "cost":"0", "accumulatedCost":"175"}
     \--- (n) -[e]-> (m) NeighborMatch {"cardinality":"146", "cost":"146", "accumulatedCost":"175"}
          \--- (n) RootVertexMatch {"cardinality":"29.2", "cost":"29.2", "accumulatedCost":"29.2"}
                WHERE $filter1
filter1: (id(n) <> 509) AND
         (id(n) <> 507) AND
         (id(n) > 500) AND
         (id(n) < 510)

前述の例では、問合せに3行を超えるフィルタがあるため、フィルタは問合せ計画の下に表示されます。フィルタが3行以下の場合、次のようにフィルタは問合せ計画ツリー内に直接表示されます。

g.explainPgql("SELECT id(n) FROM MATCH (n)-[e]->(m) WHERE " +
...> "id(n) > 500 " +
...> "AND id(n) < 510 ").print()
\--- Projection {"cardinality":"162", "cost":"0", "accumulatedCost":"194"}
     \--- (n) -[e]-> (m) NeighborMatch {"cardinality":"162", "cost":"162", "accumulatedCost":"194"}
          \--- (n) RootVertexMatch {"cardinality":"32.4", "cost":"32.4", "accumulatedCost":"32.4"}
                WHERE (id(n) > 500) AND
                      (id(n) < 510)