Vyhodnocování dotazů Gremlin s využitím kroku profilu spuštění

PLATÍ PRO: Gremlin

Tento článek obsahuje přehled použití kroku profilu spuštění pro grafové databáze Azure Cosmos DB pro Gremlin. Tento krok poskytuje relevantní informace pro účely řešení potíží a optimalizace dotazů a je kompatibilní se všemi dotazy Gremlin, které je možné spustit pro účet rozhraní Gremlin API služby Cosmos DB.

Pokud chcete tento krok použít, jednoduše připojte executionProfile() volání funkce na konec dotazu Gremlin. Váš dotaz Gremlin se provede a výsledek operace vrátí objekt odpovědi JSON s profilem provádění dotazu.

Příklad:

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

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

Po zavolání executionProfile() kroku bude odpovědí objekt JSON, který obsahuje provedený krok Gremlin, celkovou dobu trvání a pole operátorů modulu runtime cosmos DB, které příkaz způsobil.

Poznámka

Tato implementace profilu spuštění není definována ve specifikaci Apache Tinkerpop. Je specifická pro implementaci Služby Azure Cosmos DB pro Gremlin.

Příklad odpovědi

Následuje příklad výstupu s poznámkami, který se vrátí:

Poznámka

Tento příklad je opatřen poznámkami, které vysvětlují obecnou strukturu odpovědi. Skutečná odpověď executionProfile nebude obsahovat žádné komentáře.

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

Poznámka

Krok executionProfile provede dotaz Gremlin. To zahrnuje addV kroky nebo addE, které povedou k vytvoření a potvrdí změny zadané v dotazu. V důsledku toho se budou účtovat také jednotky žádostí vygenerované dotazem Gremlin.

Objekty odpovědí profilu spuštění

Odpověď funkce executionProfile() vrátí hierarchii objektů JSON s následující strukturou:

  • Objekt operace Gremlin: Představuje celou operaci Gremlin, která byla provedena. Obsahuje následující vlastnosti.

    • gremlin: Explicitní příkaz Gremlin, který byl proveden.
    • totalTime: Doba v milisekundách, ve které došlo k provedení kroku.
    • metrics: Pole, které obsahuje všechny operátory modulu runtime cosmos DB, které byly spuštěny za účelem splnění dotazu. Tento seznam je seřazený podle pořadí provedení.
  • Operátory modulu runtime služby Cosmos DB: Představují každou komponentu celé operace Gremlin. Tento seznam je seřazený podle pořadí provedení. Každý objekt obsahuje následující vlastnosti:

    • name: Název operátoru. Jedná se o typ kroku, který byl vyhodnocen a proveden. Další informace najdete v následující tabulce.
    • time: Doba v milisekundách, kterou daný operátor zabral.
    • annotations: Obsahuje další informace specifické pro operátor, který byl spuštěn.
    • annotations.percentTime: Procento z celkové doby, kterou trvalo spuštění konkrétního operátoru.
    • counts: Počet objektů, které tento operátor vrátil z vrstvy úložiště. To je obsaženo ve skalární hodnotě counts.resultCount v rámci.
    • storeOps: Představuje operaci úložiště, která může zahrnovat jeden nebo více oddílů.
    • storeOps.fanoutFactor: Představuje počet oddílů, ke kterým tato konkrétní operace úložiště přistupovala.
    • storeOps.count: Představuje počet výsledků, které tato operace úložiště vrátila.
    • storeOps.size: Představuje velikost výsledku dané operace úložiště v bajtech.
Operátor modulu runtime Gremlin služby Cosmos DB Popis
GetVertices Tento krok získá predikovanou sadu objektů z vrstvy trvalosti.
GetEdges Tento krok získá hrany, které sousedí se sadou vrcholů. Tento krok může vést k jedné nebo několika operacím úložiště.
GetNeighborVertices Tento krok získá vrcholy, které jsou připojeny k sadě hran. Hrany obsahují klíče oddílů a ID zdrojových i cílových vrcholů.
Coalesce Tento krok počítá s vyhodnocením dvou operací při každém coalesce() provedení kroku Gremlin.
CartesianProductOperator Tento krok vypočítá kartézský součin mezi dvěma datovými sadami. Obvykle se spouští vždy, když se použijí predikáty to() nebo from() .
ConstantSourceOperator Tento krok vypočítá výraz, který jako výsledek vytvoří konstantní hodnotu.
ProjectOperator Tento krok připraví a serializuje odpověď pomocí výsledku předchozích operací.
ProjectAggregation Tento krok připraví a serializuje odpověď pro agregační operaci.

Poznámka

Tento seznam bude i nadále aktualizován s tím, jak budou přidány nové operátory.

Příklady analýzy odpovědi profilu spuštění

Níže jsou uvedené příklady běžných optimalizací, které lze zjistit pomocí odpovědi profilu spuštění:

  • Nevidomý fan-out dotaz.
  • Nefiltrovaný dotaz

Vzory dotazů naslepo naslepo

Předpokládejme následující odpověď profilu spuštění z děleného grafu:

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

Z něj lze vyvodit následující závěry:

  • Dotaz je vyhledávání s jedním ID, protože příkaz Gremlin se řídí vzorem g.V('id').
  • Podle time metriky se latence tohoto dotazu zdá být vysoká, protože u jedné operace čtení bodu je vyšší než 10ms.
  • Když se podíváme na storeOps objekt , uvidíme, že fanoutFactor je 5, což znamená, že tato operace přistupovala k 5 oddílům .

Závěrem této analýzy můžeme zjistit, že první dotaz přistupuje k více oddílům, než je nutné. Můžete to vyřešit tak, že v dotazu zadáte klíč dělení jako predikát. To povede k nižší latenci a nižším nákladům na dotaz. Přečtěte si další informace o dělení grafů. Optimální dotaz by byl g.V('tt0093640').has('partitionKey', 't1001').

Nefiltrované vzory dotazů

Porovnejte následující dvě odpovědi profilu spuštění. Pro zjednodušení se v těchto příkladech používá jeden dělený graf.

Tento první dotaz načte všechny vrcholy s popiskem tweet a pak získá jejich sousední vrcholy:

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

Před prozkoumáním sousedních vrcholů si všimněte profilu stejného dotazu, ale teď s dalším filtrem 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
        }
      }
    ]
  }
]

Tyto dva dotazy dosáhly stejného výsledku, ale první z nich bude vyžadovat více jednotek žádosti, protože před dotazováním sousedních položek bylo potřeba iterovat větší počáteční datovou sadu. Indikátory tohoto chování můžeme vidět při porovnávání následujících parametrů z obou odpovědí:

  • Hodnota metrics[0].time je v první odpovědi vyšší, což značí, že vyřešení tohoto kroku trvalo déle.
  • Hodnota metrics[0].counts.resultsCount je vyšší i v první odpovědi, což značí, že počáteční pracovní datová sada byla větší.

Další kroky