Dela via


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

GÄLLER FÖR: Gremlin

Den här artikeln innehåller en översikt över hur du använder körningsprofilsteget för Azure Cosmos DB för Gremlin-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 bara till funktionsanropet executionProfile() i slutet av Gremlin-frågan. Gremlin-frågan körs och resultatet av åtgärden returnerar ett JSON-svarsobjekt med frågekörningsprofilen.

Till exempel:

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

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

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

Kommentar

Den här implementeringen för körningsprofilen definieras inte i Apache Tinkerpop-specifikationen. Det är specifikt för Azure Cosmos DB för Gremlins implementering.

Svarsexempel

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

Kommentar

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
        }
      }
    ]
  }
]

Kommentar

Steget executionProfile kör Gremlin-frågan. Detta inkluderar addV stegen eller addE, vilket resulterar i skapandet och genomför de ändringar som anges i 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 från en executionProfile()-funktion ger en hierarki med JSON-objekt med följande struktur:

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

    • gremlin: Den explicita Gremlin-instruktionen som kördes.
    • totalTime: Den tid i millisekunder som körningen av steget uppstod i.
    • metrics: En matris som innehåller var och en av Cosmos DB-körningsoperatorerna 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: Hur lång 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 lagringsskiktet av den här operatorn. Detta finns i counts.resultCount det skalära värdet i.
    • storeOps: Representerar en lagringsåtgärd som kan sträcka sig över en eller flera partitioner.
    • storeOps.fanoutFactor: Representerar antalet partitioner som den här specifika lagringsåtgärden har åtkomst till.
    • storeOps.count: Representerar 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 Operator beskrivning
GetVertices Det här steget hämtar en predikatuppsättning med objekt från beständighetsskiktet.
GetEdges Det här steget hämtar kanterna 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 hörnen som är anslutna till en uppsättning kanter. Kanterna innehåller partitionsnycklarna och ID:n för både käll- och målhörn.
Coalesce Det här steget förklarar 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() eller from() 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 hjälp av resultatet från föregående åtgärder.
ProjectAggregation Det här steget förbereder och serialiserar ett svar för en aggregeringsåtgärd.

Kommentar

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

Exempel på hur du analyserar svar på en körningsprofil

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

  • Blind-out fråga.
  • Ofiltrerad fråga.

Blinda frågemönster för utsöndrad utrullning

Anta följande svar på körningsprofilen från ett partitionerat diagram:

[
  {
    "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 av den:

  • Frågan är en enda ID-sökning eftersom Gremlin-instruktionen följer mönstret g.V('id').
  • Att döma av måttet time verkar svarstiden för den här frågan vara hög eftersom det är mer än 10 ms för en enda punktläsningsåtgärd.
  • Om vi tittar på storeOps objektet kan vi se att fanoutFactor är 5, vilket innebär att 5 partitioner användes 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 mindre svarstid och mindre kostnad per fråga. Läs mer om grafpartitionering. En mer optimal fråga skulle vara g.V('tt0093640').has('partitionKey', 't1001').

Ofiltrerade frågemönster

Jämför följande två svar för körningsprofilen. För enkelhetens skull använder de här exemplen ett enda partitionerat diagram.

Den här första frågan hämtar alla hörn med etiketten tweet och hämtar sedan sina närliggande hö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
        }
      }
    ]
  }
]

Observera 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äranden eftersom den behövde iterera en större initial datauppsättning innan du frågar efter de intilliggande objekten. Vi kan se indikatorer på det här beteendet när du 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 tog längre tid att lösa det här enskilda steget.
  • Värdet metrics[0].counts.resultsCount är också högre i det första svaret, vilket indikerar att den första arbetsdatauppsättningen var större.

Nästa steg