Lebensdauer einer Spanner-Abfrage

Kunde

Spanner unterstützt SQL-Abfragen. Hier eine Beispielabfrage:

SELECT s.SingerId, s.FirstName, s.LastName, s.SingerInfo
FROM Singers AS s
WHERE s.FirstName = @firstName;

Die Formulierung @firstName ist ein Verweis auf einen Abfrageparameter. Sie können einen Abfrageparameter überall verwenden, wo ein Literalwert verwendet werden kann. Es wird dringend empfohlen, Parameter in programmatischen APIs zu verwenden. Die Verwendung von Abfrageparametern hilft, SQL-Injection-Angriffe zu vermeiden. Die daraus resultierenden Abfragen werden eher von verschiedenen serverseitigen Caches profitieren. Siehe Caching unten.

Abfrageparameter müssen auf einen Wert begrenzt werden, wenn die Abfrage ausgeführt wird. Beispiel:

Statement statement =
    Statement.newBuilder("SELECT s.SingerId...").bind("firstName").to("Jimi").build();
try (ResultSet resultSet = dbClient.singleUse().executeQuery(statement)) {
 while (resultSet.next()) {
 ...
 }
}

Sobald Spanner einen API-Aufruf empfängt, wird die Abfrage analysiert und Parameter, um zu bestimmen, welcher Spanner-Serverknoten die Abfrage. Der Server sendet einen Stream von Ergebniszeilen zurück, die von den Aufrufen an ResultSet.next() genutzt werden.

Ausführung von Abfragen

Die Abfrageausführung beginnt mit dem Eintreffen der Anfrage „Abfrage ausführen“ auf einem beliebigen Spanner-Server. Der Server führt die folgenden Schritte aus:

  • Die Anfrage validieren
  • Den Text der Suchanfrage parsen
  • Eine erste Abfragealgebra generieren
  • Eine optimierte Abfragealgebra generieren
  • Einen ausführbaren Abfrageplan generieren
  • Den Plan ausführen (Berechtigungen überprüfen, Daten lesen, Ergebnisse codieren usw.)

Flussdiagramm Abfrageverarbeitung, das die Client-, Stamm- und Blattserver darstellt

Parsen

Der SQL-Parser analysiert den Abfragetext und wandelt ihn in eine abstrakte Syntaxstruktur um. Es extrahiert die grundlegende Abfragestruktur (SELECT … FROM … WHERE …) und führt syntaktische Prüfungen durch.

Algebra

Das Typsystem von Spanner kann Skalare, Arrays, Strukturen usw. definiert. Die Abfragealgebra definiert Operatoren für Tabellenscans, Filtern, Sortieren/Gruppieren, alle Arten von Joins, Aggregation und vieles mehr. Die ursprüngliche Abfragealgebra besteht aus der Ausgabe des Parsers. Feldnamenreferenzen in der Strukturansicht werden mit dem Datenbankschema gelöst. Dieser Code überprüft auch auf semantische Fehler (z. B. falsche Anzahl von Parametern, nicht übereinstimmende Typen usw.).

Der nächste Schritt ("Abfrageoptimierung") geht von der ersten Algebra aus und erzeugt eine optimalere Algebra. Diese kann einfacher, effizienter oder einfach besser an die Fähigkeiten der Ausführungsengine angepasst sein. Beispielsweise könnte die erste Algebra nur "Join" angeben, wobei die optimierte Algebra "Hash Join" angibt.

Ausführung

Der endgültige ausführbare Abfrageplan wird aus der neu geschriebenen Algebra erstellt. Im Grunde ist der ausführbare Plan eine gerichtete azyklische Grafik von "Iteratoren". Jeder Iterator enthält eine Wertesequenz. Iteratoren verbrauchen eventuell Eingaben, um Ausgaben zu generieren (z. B. Iterator sortieren). Abfragen mit einem einzelnen Split können von einem einzelnen Server ausgeführt werden (von dem, der die Daten enthält). Der Server scannt Bereiche verschiedener Tabellen und führt Joins, Aggregationen und alle anderen von der Abfragealgebra definierten Vorgänge aus.

Abfragen mit mehreren Splits werden in mehrere Teile einbezogen. Ein Teil der Abfrage wird weiterhin auf dem Hauptserver (Stammserver) ausgeführt. Andere partielle Unterabfragen werden an Blattknoten übergeben (die Inhaber der Splits, die gelesen werden). Diese Übergabe kann für komplexe Abfragen rekursiv angewendet werden, was zu einer Baumstruktur von Serverausführungen führt. Alle Server vereinbaren einen Zeitstempel, damit die Abfrageergebnisse ein konsistenter Snapshot der Daten sind. Jeder Blattserver gibt einen Stream von Teilergebnissen zurück. Bei Abfragen mit Aggregation können dies partiell aggregierte Ergebnisse sein. Der Abfrage-Stammserver verarbeitet die Ergebnisse von den Blatt-Servern und führt den Rest des Abfrageplans aus. Weitere Informationen finden Sie unter Abfrage-Ausführungspläne.

Wenn eine Abfrage mehrere Teilabfragen enthält, kann Spanner die Abfrage parallel über die Teilabfragen hinweg ausführen. Der Grad der Parallelität hängt vom den von der Abfrage gescannten Datenbereich, den Abfrageausführungsplan Verteilung von Daten über Splits hinweg. Spanner legt automatisch den maximalen Parallelitätsgrad für eine Abfrage basierend auf ihrer Instanzgröße und Instanzkonfiguration (regional oder multiregional) verwenden, um eine optimale Abfrageleistung vermeiden, die CPU zu überlasten.

Caching

Viele Artefakte der Abfrageverarbeitung werden automatisch im Cache gespeichert und noch einmal für alle nachfolgenden Abfragen verwendet. Dazu gehören Abfragealgebren, ausführbare Abfragepläne usw. Das Caching basiert auf dem Abfragetext, den Namen und Typen der gebundenen Parameter und so weiter. Aus diesem Grund ist die Verwendung von gebundenen Parametern wie @firstName im obigen Beispiel besser als die Verwendung von Literalwerten im Abfragetext. Erstere können einmal im Cache gespeichert werden und unabhängig vom tatsächlichen Grenzwert wiederverwendet werden. Weitere Informationen finden Sie unter Weitere Informationen finden Sie unter Spanner-Abfrageleistung optimieren.

Fehlerbehandlung

Der Stream der Ergebniszeilen aus der Methode executeQuery kann für folgende Vorgänge unterbrochen werden: beliebige Gründe: vorübergehende Netzwerkfehler, Übergabe einer Split von einem Server zu einem anderen (z.B. Load-Balancing), Serverneustarts (z.B. ein Upgrade auf eine neue Version usw. durchführen. Zur Behebung dieser Fehler Spanner sendet intransparente „Fortsetzungs-Tokens“ zusammen mit Batches von partiellen Ergebnisdaten. Diese Fortsetzungstokens können bei der Wiederholung der Abfrage zum Fortfahren verwendet werden an der Stelle, an der die unterbrochene Abfrage unterbrochen wurde. Bei Verwendung von Spanner Clientbibliotheken verwenden, geschieht dies automatisch. sodass Nutzer der Client-Bibliothek müssen Sie sich über diese Art von vorübergehenden Fehlern keine Sorgen machen.