Använda stegen i körningsprofilen för att utvärdera Gremlin-frågor

GÄLLER för: Gremlin-API

Den här artikeln innehåller en översikt över hur du använder steget körningsprofil för Azure Cosmos DB Gremlin-API-grafdatabaser. Det här steget ger relevant information för felsökning och frågekörning, och den är kompatibel med alla Gremlin-frågor som kan utföras mot ett Cosmos DB Gremlin API-konto.

Om du vill använda det här steget lägger du helt executionProfile() enkelt till funktionsanropet i slutet av Gremlin-frågan. Gremlin-frågan körs och resultatet av åtgärden returnerar ett JSON-svarsobjekt med frågekörningsprofilen.

Exempel:

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

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

När du har anropat steget är svaret ett JSON-objekt som innehåller det utförda Gremlin-steget, den totala tid det tog och en matris med de Cosmos DB-körningsoperatorer som instruktionen resulterade executionProfile() i.

Anteckning

Den här implementeringen för körningsprofil har inte definierats i Apache Tinkerpop-specifikationen. Det är specifikt Azure Cosmos DB gremlin-API:ets implementering.

Svarsexempel

Följande är ett kommenterat exempel på de utdata som returneras:

Anteckning

Det här exemplet kommenteras med kommentarer som förklarar svarets allmänna struktur. Ett faktiskt executionProfile-svar innehåller inga kommentarer.

[
  {
    // 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
        }
      }
    ]
  }
]

Anteckning

Steget executionProfile kör Gremlin-frågan. Detta inkluderar stegen eller , vilket resulterar i skapandet och kommer addV att genomföra de ändringar som anges i addE frågan. Därför debiteras även de enheter för begäran som genereras av Gremlin-frågan.

Svarsobjekt för körningsprofil

Svaret på en executionProfile()-funktion ger en hierarki med JSON-objekt med följande struktur:

  • Gremlin-åtgärdsobjekt: Representerar hela Gremlin-åtgärden som utfördes. Innehåller följande egenskaper.

    • gremlin: Den explicita Gremlin-instruktionen som kördes.
    • totalTime: Den tid, i millisekunder, som körningen av steget påfördes i.
    • metrics: En matris som innehåller var och en Cosmos DB körningsoperatorer som kördes för att uppfylla frågan. Den här listan sorteras i körningsordning.
  • Cosmos DB körningsoperatorer: Representerar var och en av komponenterna i hela Gremlin-åtgärden. Den här listan sorteras i körningsordning. Varje objekt innehåller följande egenskaper:

    • name: Namnet på operatorn. Det här är den typ av steg som utvärderades och kördes. Läs mer i tabellen nedan.
    • time: Den tid i millisekunder som en viss operator tog.
    • annotations: Innehåller ytterligare information som är specifik för operatorn som kördes.
    • annotations.percentTime: Procentandel av den totala tid det tog att köra den specifika operatorn.
    • counts: Antal objekt som returnerades från lagringslagret av den här operatorn. Detta ingår i det counts.resultCount skalära värdet i .
    • storeOps: Representerar en lagringsåtgärd som kan sträcka sig över en eller flera partitioner.
    • storeOps.fanoutFactor: Visar antalet partitioner som den här specifika lagringsåtgärden har åtkomst till.
    • storeOps.count: Visar antalet resultat som den här lagringsåtgärden returnerade.
    • storeOps.size: Representerar storleken i byte för resultatet av en viss lagringsåtgärd.
Cosmos DB Gremlin Runtime-operatorn Description
GetVertices Det här steget hämtar en angiven uppsättning objekt från beständighetsskiktet.
GetEdges Det här steget hämtar de kanter som ligger intill en uppsättning hörn. Det här steget kan resultera i en eller flera lagringsåtgärder.
GetNeighborVertices Det här steget hämtar de hörn som är anslutna till en uppsättning kanter. Kanterna innehåller partitionsnycklarna och ID:na för både käll- och målhörnen.
Coalesce Det här steget tar upp utvärderingen av två åtgärder när coalesce() Gremlin-steget körs.
CartesianProductOperator Det här steget beräknar en kartesisk produkt mellan två datauppsättningar. Körs vanligtvis när predikaten to() from() eller används.
ConstantSourceOperator Det här steget beräknar ett uttryck för att skapa ett konstant värde som ett resultat.
ProjectOperator Det här steget förbereder och serialiserar ett svar med resultatet av föregående åtgärder.
ProjectAggregation Det här steget förbereder och serialiserar ett svar för en aggregeringsåtgärd.

Anteckning

Den här listan fortsätter att uppdateras när nya operatorer läggs till.

Exempel på hur du analyserar ett svar från en körningsprofil

Följande är exempel på vanliga optimeringar som kan upptäckas med hjälp av svar från körningsprofilen:

  • Blind förfjärrfråga.
  • Ofiltrerad fråga.

Frågemönster för blind förfjädrning

Anta följande svar på körningsprofilen från en partitionerad graf:

[
  {
    "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
        }
      }
    ]
  }
]

Följande slutsatser kan dras från den:

  • Frågan är ett enda ID-uppslag, eftersom Gremlin-instruktionen följer mönstret g.V('id') .
  • Svarstiden för den här frågan verkar vara hög eftersom den är mer än 10 ms för en enda time punktläsningsåtgärd.
  • Om vi tittar på -objektet kan vi se att är , vilket storeOps fanoutFactor innebär att 5 5 partitioner kunde nås av den här åtgärden.

Som en slutsats av den här analysen kan vi fastställa att den första frågan har åtkomst till fler partitioner än nödvändigt. Detta kan åtgärdas genom att ange partitioneringsnyckeln i frågan som ett predikat. Detta leder till kortare svarstider och lägre kostnad per fråga. Läs mer om grafpartitionering. En mer optimal fråga är g.V('tt0093640').has('partitionKey', 't1001') .

Ofiltrerade frågemönster

Jämför följande två körningsprofilsvar. För enkelhetens skull använder de här exemplen en enda partitionerad graf.

Den här första frågan hämtar alla hörn med etiketten tweet och hämtar sedan sina grannhörn:

[
  {
    "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
        }
      }
    ]
  }
]

Lägg märke till profilen för samma fråga, men nu med ytterligare ett filter, has('lang', 'en') , innan du utforskar de intilliggande hörnen:

[
  {
    "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
        }
      }
    ]
  }
]

Dessa två frågor nådde samma resultat, men den första kräver fler enheter för begäran eftersom den behövde iterera en större inledande datauppsättning innan den efterfrågade intilliggande objekten. Vi kan se indikatorer för det här beteendet när vi jämför följande parametrar från båda svaren:

  • Värdet metrics[0].time är högre i det första svaret, vilket indikerar att det här steget tog längre tid att lösa.
  • Värdet metrics[0].counts.resultsCount är också högre i det första svaret, vilket indikerar att den första fungerande datauppsättningen var större.

Nästa steg