Jak użyć kroku profilu wykonywania do oceny zapytań aparatu Gremlin
DOTYCZY: Gremlin
Ten artykuł zawiera omówienie sposobu korzystania z kroku profilu wykonywania dla baz danych grafów języka Gremlin w usłudze Azure Cosmos DB. Ten krok zawiera istotne informacje dotyczące rozwiązywania problemów i optymalizacji zapytań oraz jest zgodny z dowolnymi zapytaniami Gremlin, które można wykonać względem konta interfejsu API Gremlin usługi Cosmos DB.
Aby użyć tego kroku, po prostu dołącz executionProfile()
wywołanie funkcji na końcu zapytania Gremlin. Zapytanie Gremlin zostanie wykonane , a wynik operacji zwróci obiekt odpowiedzi JSON z profilem wykonywania zapytania.
Na przykład:
// Basic traversal
g.V('mary').out()
// Basic traversal with execution profile call
g.V('mary').out().executionProfile()
Po wywołaniu executionProfile()
kroku odpowiedź będzie obiektem JSON zawierającym wykonany krok języka Gremlin, łączny czas trwania i tablicę operatorów środowiska uruchomieniowego usługi Cosmos DB, które spowodowały wykonanie instrukcji.
Uwaga
Ta implementacja profilu wykonywania nie jest zdefiniowana w specyfikacji apache Tinkerpop. Jest to specyficzne dla implementacji usługi Azure Cosmos DB dla języka Gremlin.
Przykład odpowiedzi
Poniżej znajduje się przykład z adnotacjami danych wyjściowych, które zostaną zwrócone:
Uwaga
Ten przykład jest oznaczony adnotacjami z komentarzami, które wyjaśniają ogólną strukturę odpowiedzi. Rzeczywista odpowiedź executionProfile nie będzie zawierać żadnych komentarzy.
[
{
// 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
}
}
]
}
]
Uwaga
Krok executionProfile wykona zapytanie Gremlin. Obejmuje addV
to kroki lub addE
, które spowodują utworzenie i zatwierdzą zmiany określone w zapytaniu. W związku z tym opłaty będą również naliczane za jednostki żądań wygenerowane przez zapytanie Gremlin.
Obiekty odpowiedzi profilu wykonywania
Odpowiedź funkcji executionProfile() zwróci hierarchię obiektów JSON o następującej strukturze:
Obiekt operacji języka Gremlin: reprezentuje całą wykonaną operację języka Gremlin. Zawiera następujące właściwości.
gremlin
: jawna instrukcja języka Gremlin, która została wykonana.totalTime
: czas w milisekundach, w których wykonano krok.metrics
: Tablica zawierająca każdy operator środowiska uruchomieniowego usługi Cosmos DB, który został wykonany w celu spełnienia zapytania. Ta lista jest sortowana w kolejności wykonywania.
Operatory środowiska uruchomieniowego usługi Cosmos DB: reprezentuje poszczególne składniki całej operacji języka Gremlin. Ta lista jest sortowana w kolejności wykonywania. Każdy obiekt zawiera następujące właściwości:
name
: nazwa operatora. Jest to typ kroku, który został oceniony i wykonany. Przeczytaj więcej w poniższej tabeli.time
: czas, w milisekundach, który wziął dany operator.annotations
: zawiera dodatkowe informacje specyficzne dla operatora, który został wykonany.annotations.percentTime
: procent całkowitego czasu wykonania określonego operatora.counts
: liczba obiektów zwróconych z warstwy magazynu przez ten operator. Jest to zawarte w wartości skalarnych w obrębiecounts.resultCount
.storeOps
: reprezentuje operację magazynu, która może obejmować jedną lub wiele partycji.storeOps.fanoutFactor
: reprezentuje liczbę partycji, do których uzyskiwano dostęp do tej konkretnej operacji magazynu.storeOps.count
: reprezentuje liczbę wyników zwróconych przez tę operację magazynu.storeOps.size
: reprezentuje rozmiar w bajtach wyniku danej operacji magazynu.
Operator środowiska uruchomieniowego Języka Gremlin w usłudze Cosmos DB | opis |
---|---|
GetVertices |
Ten krok uzyskuje wstępnie określony zestaw obiektów z warstwy trwałości. |
GetEdges |
Ten krok uzyskuje krawędzie sąsiadujące z zestawem wierzchołków. Ten krok może spowodować wykonanie jednej lub wielu operacji magazynowania. |
GetNeighborVertices |
Ten krok uzyskuje wierzchołki połączone z zestawem krawędzi. Krawędzie zawierają klucze partycji i identyfikatory zarówno źródłowych, jak i docelowych wierzchołków. |
Coalesce |
Ten krok obejmuje ocenę dwóch operacji przy każdym wykonaniu coalesce() kroku języka Gremlin. |
CartesianProductOperator |
Ten krok oblicza produkt kartezjański między dwoma zestawami danych. Zwykle wykonywane za każdym razem, gdy predykaty to() lub from() są używane. |
ConstantSourceOperator |
Ten krok oblicza wyrażenie w celu wygenerowania stałej wartości w wyniku. |
ProjectOperator |
Ten krok przygotowuje i serializuje odpowiedź przy użyciu wyniku poprzednich operacji. |
ProjectAggregation |
Ten krok przygotowuje i serializuje odpowiedź dla operacji agregującej. |
Uwaga
Ta lista będzie nadal aktualizowana w miarę dodawania nowych operatorów.
Przykłady dotyczące analizowania odpowiedzi profilu wykonywania
Poniżej przedstawiono przykłady typowych optymalizacji, które można wykryć przy użyciu odpowiedzi profilu wykonywania:
- Kwerenda ślepego wentylatora.
- Niefiltrowane zapytanie.
Ślepe wzorce zapytań
Załóżmy, że następująca odpowiedź profilu wykonywania z partycjonowanego 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 tego można wyciągnąć następujące wnioski:
- Zapytanie jest pojedynczym wyszukiwaniem identyfikatorów, ponieważ instrukcja Gremlin jest zgodna ze wzorcem
g.V('id')
. - Sądząc po
time
metryce, opóźnienie tego zapytania wydaje się być wysokie, ponieważ jest to ponad 10 ms dla pojedynczej operacji odczytu punktów. - Jeśli przyjrzymy się obiektowi
storeOps
, zobaczymy, że parametr to5
, co oznacza, żefanoutFactor
do tej operacji uzyskiwano dostęp do 5 partycji.
Podsumowując tę analizę, możemy określić, że pierwsze zapytanie uzyskuje dostęp do większej liczby partycji, niż jest to konieczne. Można to rozwiązać, określając klucz partycjonowania w zapytaniu jako predykat. Doprowadzi to do mniejszego opóźnienia i mniejszego kosztu na zapytanie. Dowiedz się więcej o partycjonowaniu grafu. Bardziej optymalne zapytanie to g.V('tt0093640').has('partitionKey', 't1001')
.
Niefiltrowane wzorce zapytań
Porównaj następujące dwie odpowiedzi profilu wykonywania. Dla uproszczenia w tych przykładach użyto pojedynczego partycjonowanego grafu.
To pierwsze zapytanie pobiera wszystkie wierzchołki z etykietą tweet
, a następnie uzyskuje sąsiadujące wierzchołki:
[
{
"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
}
}
]
}
]
Zwróć uwagę na profil tego samego zapytania, ale teraz z dodatkowym filtrem , has('lang', 'en')
przed eksplorowanie sąsiednich wierzchołków:
[
{
"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
}
}
]
}
]
Te dwa zapytania osiągnęły ten sam wynik, jednak pierwsza z nich będzie wymagać większej liczby jednostek żądania, ponieważ wymaga iteracji większego początkowego zestawu danych przed wykonaniem zapytania o sąsiadujące elementy. Możemy zobaczyć wskaźniki tego zachowania podczas porównywania następujących parametrów z obu odpowiedzi:
- Wartość
metrics[0].time
jest wyższa w pierwszej odpowiedzi, co oznacza, że ten pojedynczy krok trwał dłużej. - Wartość
metrics[0].counts.resultsCount
jest wyższa, jak również w pierwszej odpowiedzi, co oznacza, że początkowy roboczy zestaw danych był większy.
Następne kroki
- Dowiedz się więcej o obsługiwanych funkcjach języka Gremlin w usłudze Azure Cosmos DB.
- Dowiedz się więcej o interfejsie API języka Gremlin w usłudze Azure Cosmos DB.