如何使用執行設定檔步驟來評估您的 Gremlin 查詢

適用於: Gremlin

此文章概述如何使用 Azure Cosmos DB for Gremlin 圖形資料庫的執行設定檔步驟。 此步驟提供疑難排解和查詢最佳化的相關資訊,並與可針對 Cosmos DB Gremlin API 帳戶執行的任何 Gremlin 查詢相容。

若要使用此步驟,只要在 Gremlin 查詢結尾附加 executionProfile() 函式呼叫即可。 您的 Gremlin 查詢將會執行,而且此作業的結果將傳回具有查詢執行設定檔的 JSON 回應物件。

例如:

    // Basic traversal
    g.V('mary').out()

    // Basic traversal with execution profile call
    g.V('mary').out().executionProfile()

呼叫 executionProfile() 步驟之後,回應會是一個 JSON 物件,其中包括已執行的 Gremlin 步驟、所花費的總時間,以及陳述式所產生的 Cosmos DB 執行階段運算子陣列。

注意

此執行設定檔實作並未定義於 Apache Tinkerpop 規格中。 其特定於 Azure Cosmos DB for Gremlin 的實作。

回應範例

以下是將傳回的已標註輸出範例:

注意

此範例會使用可說明回應一般結構的註解來標註。 實際的 executionProfile 回應不會包含任何註解。

[
  {
    // The Gremlin statement that was executed.
    "gremlin": "g.V('mary').out().executionProfile()",

    // Amount of time in milliseconds that the entire operation took.
    "totalTime": 28,

    // An array containing metrics for each of the steps that were executed. 
    // Each Gremlin step will translate to one or more of these steps.
    // This list is sorted in order of execution.
    "metrics": [
      {
        // This operation obtains a set of Vertex objects.
        // The metrics include: time, percentTime of total execution time, resultCount, 
        // fanoutFactor, count, size (in bytes) and time.
        "name": "GetVertices",
        "time": 24,
        "annotations": {
          "percentTime": 85.71
        },
        "counts": {
          "resultCount": 2
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 2,
            "size": 696,
            "time": 0.4
          }
        ]
      },
      {
        // This operation obtains a set of Edge objects. 
        // Depending on the query, these might be directly adjacent to a set of vertices, 
        // or separate, in the case of an E() query.
        //
        // The metrics include: time, percentTime of total execution time, resultCount, 
        // fanoutFactor, count, size (in bytes) and time.
        "name": "GetEdges",
        "time": 4,
        "annotations": {
          "percentTime": 14.29
        },
        "counts": {
          "resultCount": 1
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 1,
            "size": 419,
            "time": 0.67
          }
        ]
      },
      {
        // This operation obtains the vertices that a set of edges point at.
        // The metrics include: time, percentTime of total execution time and resultCount.
        "name": "GetNeighborVertices",
        "time": 0,
        "annotations": {
          "percentTime": 0
        },
        "counts": {
          "resultCount": 1
        }
      },
      {
        // This operation represents the serialization and preparation for a result from 
        // the preceding graph operations. The metrics include: time, percentTime of total 
        // execution time and resultCount.
        "name": "ProjectOperator",
        "time": 0,
        "annotations": {
          "percentTime": 0
        },
        "counts": {
          "resultCount": 1
        }
      }
    ]
  }
]

注意

executionProfile 步驟將執行 Gremlin 查詢。 這包括 addVaddE 步驟,其將導致建立並認可查詢中所指定的變更。 因此,Gremlin 查詢所產生的要求單位也需收費。

執行設定檔回應物件

executionProfile() 函式的回應會產生具有下列結構的 JSON 物件階層:

  • Gremlin 作業物件:代表已執行的整個 Gremlin 作業。 包含下列屬性。

    • gremlin:已執行的明確 Gremlin 陳述式。
    • totalTime:執行步驟的時間 (以毫秒為單位)。
    • metrics:包含為滿足查詢而執行的每個 Cosmos DB 執行階段運算子的陣列。 此清單會依執行順序排序。
  • Cosmos DB 執行階段運算子:代表整個 Gremlin 作業的每個元件。 此清單會依執行順序排序。 每個物件均包含下列屬性:

    • name:運算子的名稱。 這是已評估並執行的步驟類型。 詳情請參閱下表。
    • time:指定運算子所花費的時間 (以毫秒為單位)。
    • annotations:包含已執行之運算子特有的其他資訊。
    • annotations.percentTime:執行特定運算子所花費的總時間百分比。
    • counts:此運算子從儲存層傳回的物件數目。 這會包含在 counts.resultCount 純量值中。
    • storeOps:表示可跨越一或多個分割區的儲存體作業。
    • storeOps.fanoutFactor:表示此特定儲存體作業存取的分割區數目。
    • storeOps.count:表示此儲存體作業傳回的結果數。
    • storeOps.size:表示指定儲存體作業的結果大小 (以位元組為單位)。
Cosmos DB Gremlin 執行階段運算子 描述
GetVertices 此步驟會從持續層取得一組具有述詞的物件。
GetEdges 此步驟會取得與一組頂點相鄰的邊緣。 此步驟可能會產生一或多個儲存體作業。
GetNeighborVertices 此步驟會取得連接至一組邊緣的頂點。 邊緣包含其來源和目標頂點的分割區索引鍵與識別碼。
Coalesce 每次執行 coalesce() Gremlin 步驟時,此步驟都會用於評估兩個作業。
CartesianProductOperator 此步驟會計算兩個資料集之間的笛卡兒乘積。 通常會在每次使用述詞 to()from() 時執行。
ConstantSourceOperator 此步驟會計算運算式,來產生一個常數值作為結果。
ProjectOperator 此步驟會使用上述作業的結果來準備和序列化回應。
ProjectAggregation 此步驟會針對彙總作業準備和序列化回應。

注意

此清單會繼續隨著運算子新增而更新。

如何分析執行設定檔回應的範例

以下是可使用執行設定檔回應找出的常見最佳化範例:

  • 盲目展開傳送查詢。
  • 未篩選的查詢。

盲目展開傳送查詢模式

假設下列執行設定檔回應來自資料分割圖表

[
  {
    "gremlin": "g.V('tt0093640').executionProfile()",
    "totalTime": 46,
    "metrics": [
      {
        "name": "GetVertices",
        "time": 46,
        "annotations": {
          "percentTime": 100
        },
        "counts": {
          "resultCount": 1
        },
        "storeOps": [
          {
            "fanoutFactor": 5,
            "count": 1,
            "size": 589,
            "time": 75.61
          }
        ]
      },
      {
        "name": "ProjectOperator",
        "time": 0,
        "annotations": {
          "percentTime": 0
        },
        "counts": {
          "resultCount": 1
        }
      }
    ]
  }
]

可以由此得出下列結論:

  • 此查詢是單一識別碼查閱,因為 Gremlin 陳述式遵循 g.V('id') 模式。
  • time 計量判斷,此查詢的延遲似乎很高,因為其對單點讀取作業來說多出 10 毫秒
  • 觀察 storeOps 物件,可以看到 fanoutFactor5,這表示此作業存取了 5 個分割區

為此分析做結論,我們可以判斷第一個查詢所存取的分割區數量超出所需。 將查詢中的分割區索引鍵指定為述詞,即可解決此問題。 這會導致較低的延遲,而且每個查詢的成本比較低。 深入了解圖表分割。 較理想的查詢是 g.V('tt0093640').has('partitionKey', 't1001')

未篩選的查詢模式

比較下列兩個執行設定檔回應。 為了簡單起見,這些範例會使用單一資料分割圖表。

第一個查詢會擷取具有 tweet 標籤的所有頂點,然後取得其相鄰頂點:

[
  {
    "gremlin": "g.V().hasLabel('tweet').out().executionProfile()",
    "totalTime": 42,
    "metrics": [
      {
        "name": "GetVertices",
        "time": 31,
        "annotations": {
          "percentTime": 73.81
        },
        "counts": {
          "resultCount": 30
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 13,
            "size": 6819,
            "time": 1.02
          }
        ]
      },
      {
        "name": "GetEdges",
        "time": 6,
        "annotations": {
          "percentTime": 14.29
        },
        "counts": {
          "resultCount": 18
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 20,
            "size": 7950,
            "time": 1.98
          }
        ]
      },
      {
        "name": "GetNeighborVertices",
        "time": 5,
        "annotations": {
          "percentTime": 11.9
        },
        "counts": {
          "resultCount": 20
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 4,
            "size": 1070,
            "time": 1.19
          }
        ]
      },
      {
        "name": "ProjectOperator",
        "time": 0,
        "annotations": {
          "percentTime": 0
        },
        "counts": {
          "resultCount": 20
        }
      }
    ]
  }
]

探索相鄰頂點之前,請注意相同查詢的設定檔,但現在具有額外的篩選條件 has('lang', 'en')

[
  {
    "gremlin": "g.V().hasLabel('tweet').has('lang', 'en').out().executionProfile()",
    "totalTime": 14,
    "metrics": [
      {
        "name": "GetVertices",
        "time": 14,
        "annotations": {
          "percentTime": 58.33
        },
        "counts": {
          "resultCount": 11
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 11,
            "size": 4807,
            "time": 1.27
          }
        ]
      },
      {
        "name": "GetEdges",
        "time": 5,
        "annotations": {
          "percentTime": 20.83
        },
        "counts": {
          "resultCount": 18
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 18,
            "size": 7159,
            "time": 1.7
          }
        ]
      },
      {
        "name": "GetNeighborVertices",
        "time": 5,
        "annotations": {
          "percentTime": 20.83
        },
        "counts": {
          "resultCount": 18
        },
        "storeOps": [
          {
            "fanoutFactor": 1,
            "count": 4,
            "size": 1070,
            "time": 1.01
          }
        ]
      },
      {
        "name": "ProjectOperator",
        "time": 0,
        "annotations": {
          "percentTime": 0
        },
        "counts": {
          "resultCount": 18
        }
      }
    ]
  }
]

這兩個查詢會得到相同結果,但第一個查詢需要更多要求單位,因為查詢相鄰項目之前,其需要先逐一查看較大型的初始資料集。 從這兩個回應比較下列參數,可以看出這種行為的指標:

  • 第一個回應中的 metrics[0].time 值較高,表示這個單一步驟花費較長的時間來解析。
  • 第一個回應中的 metrics[0].counts.resultsCount 值也較高,這表示初始工作資料集比較大。

下一步