Wie in Abfrageausführungspläne beschrieben, transformiert der SQL-Compiler eine SQL-Anweisung in einen Abfrageausführungsplan, der verwendet wird, um die Ergebnisse der Abfrage zu erhalten. Auf dieser Seite werden Best Practices für SQL-Anweisungen erstellen, um Spanner dabei zu helfen, eine effiziente Ausführung zu finden Pläne.
Die Beispiel-SQL-Anweisungen auf dieser Seite verwenden das folgende Beispielschema:
GoogleSQL
CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo BYTES(MAX),
BirthDate DATE
) PRIMARY KEY (SingerId);
CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX),
ReleaseDate DATE
) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE;
Die vollständige SQL-Referenz finden Sie unter Anweisungssyntax, Funktionen und Operatoren und Lexikalische Struktur und Syntax.
PostgreSQL
CREATE TABLE Singers (
SingerId BIGINT PRIMARY KEY,
FirstName VARCHAR(1024),
LastName VARCHAR(1024),
SingerInfo BYTEA,
BirthDate TIMESTAMPTZ
);
CREATE TABLE Albums (
SingerId BIGINT NOT NULL,
AlbumId BIGINT NOT NULL,
AlbumTitle VARCHAR(1024),
ReleaseDate DATE,
PRIMARY KEY(SingerId, AlbumId),
FOREIGN KEY (SingerId) REFERENCES Singers(SingerId)
) INTERLEAVE IN PARENT Singers ON DELETE CASCADE;
Weitere Informationen finden Sie unter PostgreSQL-Sprache in Spanner.
Abfrageparameter verwenden
Spanner unterstützt Abfrageparameter, um die Leistung zu steigern und Hilfe zu erhalten SQL-Injection zu verhindern, wenn Abfragen über Nutzereingaben erstellt werden. Sie können Abfrageparameter als Ersatz für beliebige Ausdrücke verwenden, aber nicht als Ersatz für Kennzeichnungen, Spaltennamen, Tabellennamen oder andere Teile der Abfrage.
Parameter können überall dort vorkommen, wo ein Literalwert erwartet wird. Das Gleiche Parametername kann mehrfach in einer einzelnen SQL-Anweisung verwendet werden.
Zusammenfassend haben Abfrageparameter folgende Vorteile für die Abfrageausführung:
- Voroptimierte Pläne: Abfragen, die Parameter verwenden, können auf jeden Aufruf, da die Parametrisierung die Spanner den Ausführungsplan im Cache zu speichern.
- Vereinfachte Abfragezusammensetzung: Sie müssen Stringwerte nicht ausschließen, wenn Sie sie in Abfrageparametern bereitstellen. Abfrageparameter verringern auch das Risiko von Syntaxfehlern.
- Sicherheit: Abfrageparameter machen Ihre Abfragen sicherer, da sie Sie schützen SQL-Injection-Angriffen zu schützen. Dieser Schutz ist besonders wichtig für Abfragen, die Sie aus Nutzereingaben erstellen.
So werden Abfragen von Spanner ausgeführt
Mit Spanner können Sie Datenbanken mithilfe von deklarativen SQL-Anweisungen abfragen die angeben, welche Daten Sie abrufen möchten. Wenn Sie wissen möchten, wie Spanner die Ergebnisse erhält, sehen Sie sich den Ausführungsplan für die Abfrage an. Ein Abfrageausführungsplan zeigt die mit jedem Schritt der Abfrage verbundenen Berechnungskosten an. Mit diesen Kosten können Sie Leistungsprobleme bei Abfragen beheben und Ihre Abfrage optimieren. Weitere Informationen finden Sie unter Abfrage-Ausführungspläne.
Abfrageausführungspläne können über die Google Cloud Console oder Clientbibliotheken
So rufen Sie mit der Google Cloud Console einen Abfrageausführungsplan für eine bestimmte Abfrage ab:
Öffnen Sie die Seite „Spanner-Instanzen“.
Wählen Sie die Namen der Spanner-Instanz und der Datenbank aus, die Sie abfragen möchten.
Klicken Sie im linken Navigationsbereich auf Spanner Studio.
Geben Sie die Abfrage in das Textfeld ein und klicken Sie auf Abfrage ausführen.
Klicken Sie auf Erläuterung
. Die Google Cloud Console zeigt einen visuellen Ausführungsplan für die Abfrage an.
Weitere Informationen zum Verständnis visueller Pläne und deren Verwendung zur Fehlerbehebung Siehe Abfragen mit dem Abfrageplan-Visualizer abstimmen.
Sie können sich auch Beispiele für bisherige Abfragepläne ansehen und die Leistung vergleichen für bestimmte Abfragen im Zeitverlauf. Weitere Informationen finden Sie unter Stichprobenabfragepläne:
Sekundäre Indexe verwenden
Wie andere relationale Datenbanken bietet Spanner sekundäre Indexe, mit denen Sie Daten entweder mithilfe einer SQL-Anweisung oder mithilfe der Leseoberfläche von Spanner abrufen können. Die gängigere Methode zum Abrufen von Daten aus einem Index ist die Verwendung von Spanner Studio. Mit einem sekundären Index in einer SQL-Abfrage können Sie angeben, wie Spanner die Ergebnisse erhalten soll. Das Angeben eines sekundären Index kann die Ausführung von Abfragen beschleunigen.
Angenommen, Sie möchten die IDs aller Sänger mit einem bestimmten Nachnamen abrufen. Hier ist eine Möglichkeit, eine solche SQL-Abfrage zu schreiben:
SELECT s.SingerId
FROM Singers AS s
WHERE s.LastName = 'Smith';
Diese Abfrage würde die erwarteten Ergebnisse zurückgeben. Es kann jedoch lange dauern. Die Dauer hängt von der Anzahl der Zeilen in der Tabelle Singers
ab und davon, wie viele das Prädikat WHERE s.LastName = 'Smith'
erfüllen. Wenn es keinen sekundären Index gibt, der die Spalte LastName
enthält, aus der gelesen werden soll, liest der Abfrageplan die gesamte Tabelle Singers
, um Zeilen zu finden, die mit dem Prädikat übereinstimmen. Das Lesen der gesamten Tabelle wird als vollständiger Tabellenscan bezeichnet. Ein Scan der gesamten Tabelle ist teuer
wenn die Tabelle nur einen kleinen Prozentsatz
Singers
mit diesem Nachnamen.
Sie können die Leistung dieser Abfrage verbessern, wenn Sie einen sekundären Index für die Nachname-Spalte definieren:
CREATE INDEX SingersByLastName ON Singers (LastName);
Da der sekundäre Index SingersByLastName
die indexierte Tabellenspalte LastName
und die Primärschlüsselspalte SingerId
enthält, kann Spanner alle Daten aus der wesentlich kleineren Indextabelle abrufen, ohne die gesamte Tabelle Singers
scannen zu müssen.
In diesem Szenario verwendet Spanner automatisch den sekundären Index SingersByLastName
während der Ausführung der Abfrage (sofern drei Tage seit der Datenbankerstellung vergangen sind; siehe Hinweis zu neuen Datenbanken). Als Best Practice hat es sich jedoch bewährt, Spanner diesen Index explizit anzugeben. Legen Sie dazu in der Klausel FROM
eine Indexanweisung fest:
GoogleSQL
SELECT s.SingerId
FROM Singers@{FORCE_INDEX=SingersByLastName} AS s
WHERE s.LastName = 'Smith';
PostgreSQL
SELECT s.SingerId
FROM Singers /*@ FORCE_INDEX=SingersByLastName */ AS s
WHERE s.LastName = 'Smith';
Beispiel: Sie wollten neben der ID auch den Vornamen des Sängers abrufen. Auch wenn die Spalte FirstName
nicht im Index enthalten ist, sollten Sie die Indexanweisung wie zuvor angeben:
GoogleSQL
SELECT s.SingerId, s.FirstName
FROM Singers@{FORCE_INDEX=SingersByLastName} AS s
WHERE s.LastName = 'Smith';
PostgreSQL
SELECT s.SingerId, s.FirstName
FROM Singers /*@ FORCE_INDEX=SingersByLastName */ AS s
WHERE s.LastName = 'Smith';
Sie erhalten immer noch einen Leistungsvorteil bei der Verwendung des Index, da Spanner beim Ausführen des Abfrageplans keinen vollständigen Tabellenscan machen muss. Stattdessen werden sie
Wählt die Teilmenge der Zeilen aus, die das Prädikat aus SingersByLastName
erfüllen
und führt dann eine Suche aus der Basistabelle Singers
durch, um die erste
und zwar nur für diese Teilmenge der Zeilen.
Wenn Spanner keine Zeilen aus der Basis abrufen muss
überhaupt nicht verwenden, können Sie eine Kopie der Spalte FirstName
im
den Index selbst:
GoogleSQL
CREATE INDEX SingersByLastName ON Singers (LastName) STORING (FirstName);
PostgreSQL
CREATE INDEX SingersByLastName ON Singers (LastName) INCLUDE (FirstName);
Die Verwendung einer STORING
-Klausel (für den GoogleSQL-Dialekt) oder einer INCLUDE
-Klausel (für den PostgreSQL-Dialekt) kostet zwar zusätzlichen Speicher, bietet jedoch die folgenden Vorteile:
- SQL-Abfragen, die den Index verwenden und Spalten auswählen, die in
STORING
oderINCLUDE
-Klausel erfordert keine zusätzliche Verknüpfung mit der Basistabelle. - Leseaufrufe, die den Index verwenden, können Spalten lesen, die im
STORING
oderINCLUDE
-Klausel angegeben werden.
Die Beispiele oben zeigen, wie sekundäre Indexe Abfragen beschleunigen können, wenn die von der WHERE
-Klausel einer Abfrage ausgewählten Zeilen mit dem sekundären Index schnell identifiziert werden können.
Ein weiteres Szenario, in dem sekundäre Indexe Leistungsvorteile bieten können, sind bestimmte Abfragen, die geordnete Ergebnisse zurückgeben. Angenommen, Sie möchten alle Albumtitel und ihre Veröffentlichungsdaten aufsteigend nach Veröffentlichungsdatum und absteigend nach Albumtitel abrufen. So könnten Sie eine SQL-Abfrage schreiben:
SELECT a.AlbumTitle, a.ReleaseDate
FROM Albums AS a
ORDER BY a.ReleaseDate, a.AlbumTitle DESC;
Ohne einen sekundären Index erfordert diese Abfrage möglicherweise einen teuren Sortierschritt im Ausführungsplan. Sie können die Abfrageausführung beschleunigen, wenn Sie diesen sekundären Index definieren:
CREATE INDEX AlbumsByReleaseDateTitleDesc on Albums (ReleaseDate, AlbumTitle DESC);
Schreiben Sie die Abfrage dann neu, um den sekundären Index zu verwenden:
GoogleSQL
SELECT a.AlbumTitle, a.ReleaseDate
FROM Albums@{FORCE_INDEX=AlbumsByReleaseDateTitleDesc} AS a
ORDER BY a.ReleaseDate, a.AlbumTitle DESC;
PostgreSQL
SELECT a.AlbumTitle, a.ReleaseDate
FROM Albums /*@ FORCE_INDEX=AlbumsByReleaseDateTitleDesc */ AS s
ORDER BY a.ReleaseDate, a.AlbumTitle DESC;
Diese Abfrage und diese Indexdefinition erfüllen die folgenden zwei Kriterien:
- Wenn Sie den Sortierschritt entfernen möchten, muss die Spaltenliste im
ORDER BY
ist ein Präfix der Indexschlüsselliste. - Um zu vermeiden, dass aus der Basistabelle eine Verbindung hergestellt wird, um fehlende Spalten abzurufen, dass der Index alle Spalten in der Tabelle abdeckt, die von der Abfrage verwendet werden.
Sekundäre Indizes können häufige Abfragen beschleunigen. Das Hinzufügen von sekundären Indizes kann jedoch zu Verzögerungen bei den Commit-Vorgängen führen, da für jeden sekundären Index in der Regel ein zusätzlicher Knoten bei jedem Commit erforderlich ist. Bei den meisten Arbeitslasten ist es ausreichend, einige wenige sekundäre Indizes zu haben. Sie sollten jedoch überlegen, ob Ihnen Leselatenz oder Schreiblatenz wichtiger ist und welche Vorgänge für Ihre Arbeitslast am wichtigsten sind. Benchmarking durchführen um sicherzustellen, dass sie erwartungsgemäß funktioniert.
Die vollständige Referenz zu sekundären Indexen finden Sie unter Sekundäre Indexe.
Scans optimieren
Bestimmte Spanner-Abfragen könnten von der Verwendung eines Batch-orientierten beim Scannen von Daten statt mit der gebräuchlicheren zeilenorientierten Datenverarbeitungsmethode. Die Batchverarbeitung von Scans ist eine effizientere Methode, gleichzeitig große Datenmengen verarbeitet und Abfragen können eine geringere CPU-Auslastung und eine geringere Latenz.
Der Spanner-Suchvorgang beginnt die Ausführung immer im zeilenorientierten Modus. Während dieser Zeit erfasst Spanner mehrere Laufzeitmesswerte. Anschließend wendet Spanner eine Reihe von Heuristiken an, die auf dem Ergebnis dieser Messwerte basieren, um den optimalen Scanmodus zu ermitteln. Wann? wechselt Spanner in einen Batch-orientierten Verarbeitungsmodus, um Durchsatz und Leistung von Scans zu verbessern.
Gängige Anwendungsfälle
Bei Abfragen mit den folgenden Merkmalen ist die batchorientierte Verarbeitung im Allgemeinen vorteilhaft:
- Große Scans von selten aktualisierten Daten.
- Scannt mit Prädikaten für Spalten mit fester Breite.
- Scans mit einer großen Anzahl von Suchvorgängen. Bei einer Suche wird ein Index verwendet, um Einträge abzurufen.
Anwendungsfälle ohne Leistungssteigerung
Nicht alle Abfragen profitieren von einer Batch-orientierten Verarbeitung. Bei den folgenden Abfragetypen ist die Leistung bei der zeilenorientierten Scanverarbeitung höher:
- Punktsuchabfragen: Abfragen, die nur eine Zeile abrufen.
- Kleine Scanabfragen: Tabellenscans, bei denen nur wenige Zeilen gescannt werden, es sei denn, die Anzahl der Suchvorgänge ist hoch.
- Abfragen, bei denen
LIMIT
verwendet wird. - Abfragen mit vielen Daten zum Kundenabbruch: Bei diesen Abfragen werden mehr als 10 % der gelesenen Daten häufig aktualisiert.
- Abfragen mit Zeilen mit großen Werten: Zeilen mit großen Werten enthalten Werte, die größer als 32.000 Byte (vor der Komprimierung) in einer einzelnen Spalte sind.
Von einer Abfrage verwendete Scanmethode prüfen
So prüfen Sie, ob für Ihre Abfrage die batchorientierte Verarbeitung, die zeilenorientierte Verarbeitung oder der automatische Wechsel zwischen den beiden Scanmethoden verwendet wird:
Rufen Sie in der Google Cloud Console die Seite Spanner-Instanzen auf.
Klicken Sie auf den Namen der Instanz mit der Abfrage, die Sie untersuchen möchten.
Klicken Sie in der Tabelle „Datenbanken“ auf die Datenbank mit der Abfrage, die Sie untersuchen möchten.
Klicken Sie im Navigationsmenü auf Spanner Studio.
Neuen Tab durch Klicken auf
öffnen Neuer SQL-Editor-Tab oder Neuer Tab:Schreiben Sie Ihre Abfrage, sobald der Abfrageeditor angezeigt wird.
Klicken Sie auf Ausführen.
Spanner führt die Abfrage aus und zeigt die Ergebnisse an.
Klicken Sie unter dem Abfrageeditor auf den Tab Erläuterung.
Spanner zeigt eine Visualisierung des Ausführungsplans eines Abfrageplans. Jede Karte im Diagramm steht für einen Iterator.
Klicken Sie auf die Karte „Tabellenscan“, um ein Infofeld zu öffnen.
Im Infobereich werden Kontextinformationen angezeigt. über den ausgewählten Scan. Die Scanmethode wird auf dieser Karte angezeigt. Automatisch gibt an, dass Spanner die Scanmethode bestimmt. Weitere mögliche Werte sind Vectorized (Vektorisiert) für die batchorientierte Verarbeitung und Scalar (Skalar) für die zeilenorientierte Verarbeitung.
Scanmethode für eine Abfrage erzwingen
Zur Optimierung der Abfrageleistung wählt Spanner den optimalen Scan aus -Methode für Ihre Abfrage hinzu. Wir empfehlen, diese Standard-Scanmethode zu verwenden. Es kann jedoch Fälle geben, in denen Sie eine bestimmte Art der Scanmethode erzwingen möchten.
Batchorientiertes Scannen erzwingen
Sie können Batch-orientiertes Scannen auf Tabellen- und Anweisungsebene erzwingen.
Wenn Sie die batchorientierte Scanmethode auf Tabellenebene erzwingen möchten, verwenden Sie in Ihrer Abfrage einen Tabellenhinweis:
GoogleSQL
SELECT ...
FROM (t1@{SCAN_METHOD=BATCH} JOIN t2 ON ...)
WHERE ...
PostgreSQL
SELECT ...
FROM (t1/*@ scan_method=batch */ JOIN t2 on ...)
WHERE ...
Wenn Sie die batchorientierte Scanmethode auf Anweisungsebene erzwingen möchten, verwenden Sie in Ihrer Abfrage einen Anweisungshinweis:
GoogleSQL
@{SCAN_METHOD=BATCH}
SELECT ...
FROM ...
WHERE ...
PostgreSQL
/*@ scan_method=batch */
SELECT ...
FROM ...
WHERE ...
So deaktivieren Sie das automatische Scannen und erzwingen das zeilenorientierte Scannen
Auch wenn wir nicht raten, die automatische Auswahlmethode zu deaktivieren, können Sie das Tool deaktivieren und die Methode zeilenorientierte Auswahlmethode zur Fehlerbehebung, z. B. für die Diagnose Latenz.
Um die automatische Scanmethode zu deaktivieren und die Zeilenverarbeitung in der Tabelle zu erzwingen Ebene verwenden, verwenden Sie einen Tabellenhinweis in Ihrer Abfrage:
GoogleSQL
SELECT ...
FROM (t1@{SCAN_METHOD=ROW} JOIN t2 ON ...)
WHERE ...
PostgreSQL
SELECT ...
FROM (t1/*@ scan_method=row */ JOIN t2 on ...)
WHERE ...
Wenn Sie die automatische Scanmethode deaktivieren und die Zeilenverarbeitung auf Anweisungsebene erzwingen möchten, verwenden Sie einen Anweisungshinweis in Ihrer Abfrage:
GoogleSQL
@{SCAN_METHOD=ROW}
SELECT ...
FROM ...
WHERE ...
PostgreSQL
/*@ scan_method=row */
SELECT ...
FROM ...
WHERE ...
Suchanfragen für Bereichsschlüssel optimieren
Eine häufige Verwendung einer SQL-Abfrage ist das Lesen mehrerer Zeilen aus Spanner-basierten bekannten Schlüsseln stehen.
Die folgenden Best Practices helfen Ihnen beim Schreiben effizienter Abfragen beim Abrufen von Daten mit einem Schlüsselbereich:
Wenn die Liste der Schlüssel kurz ist und keine benachbarten Schlüssel enthält, verwenden Sie Abfrageparameter und
UNNEST
zur Erstellung der Abfrage.Wenn die Schlüsselliste beispielsweise
{1, 5, 1000}
lautet, schreiben Sie die Abfrage so:GoogleSQL
SELECT * FROM Table AS t WHERE t.Key IN UNNEST (@KeyList)
PostgreSQL
SELECT * FROM Table AS t WHERE t.Key IN UNNEST ($1)
Hinweise:
Der Operator Array UNNEST vereinfacht ein Eingabe-Array so, dass es in Zeilen von Elementen vorliegt.
Der Abfrageparameter
@KeyList
für GoogleSQL und$1
für PostgreSQL kann die Abfrage beschleunigen, wie in der vorangehenden Best Practice beschrieben.
Wenn die Liste der Schlüssel benachbarte Schlüssel enthält und innerhalb eines Bereichs liegt, geben Sie die untere und obere Grenze des Schlüsselbereichs in der Klausel
WHERE
an.Wenn die Schlüsselliste beispielsweise
{1,2,3,4,5}
lautet, erstellen Sie die Abfrage so:GoogleSQL
SELECT * FROM Table AS t WHERE t.Key BETWEEN @min AND @max
PostgreSQL
SELECT * FROM Table AS t WHERE t.Key BETWEEN $1 AND $2
Diese Abfrage ist nur effizienter, wenn die Schlüssel im Schlüsselbereich benachbart sind. Mit anderen Worten: Wenn Ihre Schlüsselliste
{1, 5, 1000}
ist, wie in der vorherigen Abfrage die Unter- und Obergrenze angeben, würde jeder Wert zwischen 1 und 1000 durchgehen.
Optimize-Verknüpfungen
Join-Vorgänge können teuer sein, da sie die Anzahl der Zeilen, die Ihre Abfrage scannen muss, erheblich erhöhen können. Dies führt zu langsameren Abfragen. Zusätzlich zu den Methoden, die Sie in anderen relationalen Datenbanken zum Optimieren von Join-Abfragen verwenden, finden Sie hier einige Best Practices für einen effizienteren JOIN bei der Verwendung von Spanner SQL:
Verbinden Sie nach Möglichkeit Daten in verschränkten Tabellen mit dem Primärschlüssel. Beispiel:
SELECT s.FirstName, a.ReleaseDate FROM Singers AS s JOIN Albums AS a ON s.SingerId = a.SingerId;
Die Zeilen in der verschränkten Tabelle
Albums
werden in denselben Splits wie die übergeordnete Zeile inSingers
gespeichert, wie in Schema und Datenmodell erläutert. Joins können daher ohne große Datenmengen über das Netzwerk zu senden.Verwenden Sie die Join-Anweisung, wenn Sie die Reihenfolge des Joins erzwingen möchten. Beispiel:
GoogleSQL
SELECT * FROM Singers AS s JOIN@{FORCE_JOIN_ORDER=TRUE} Albums AS a ON s.SingerId = a.Singerid WHERE s.LastName LIKE '%x%' AND a.AlbumTitle LIKE '%love%';
PostgreSQL
SELECT * FROM Singers AS s JOIN/*@ FORCE_JOIN_ORDER=TRUE */ Albums AS a ON s.SingerId = a.Singerid WHERE s.LastName LIKE '%x%' AND a.AlbumTitle LIKE '%love%';
Die Join-Anweisung
FORCE_JOIN_ORDER
weist Spanner an, die in der Abfrage angegebene Join-Reihenfolge zu verwenden (d. h.Singers JOIN Albums
, nichtAlbums JOIN Singers
). Die zurückgegebenen Ergebnisse sind unabhängig von der Reihenfolge, die Spanner auswählt, identisch. Sie sollten diese Join-Anweisung allerdings verwenden, wenn Sie im Abfrageplan bemerken, dass Spanner die Join-Reihenfolge geändert und unerwünschte Folgen verursacht hat, z. B. dass größere Zwischenergebnisse erzielt oder dass Gelegenheiten zum Suchen von Zeilen verpasst wurden.Wählen Sie mit einer Join-Anweisung eine Join-Implementierung aus. Wenn Sie mit SQL mehrere Tabellen abfragen, verwendet Spanner automatisch eine Join-Methode, durch die die Abfrage wahrscheinlich effizienter wird. Google empfiehlt jedoch, mit verschiedenen Join-Algorithmen zu testen. Wenn Sie den richtigen Join-Algorithmus auswählen, können Latenz, Speicherverbrauch oder beides verbessert werden. Diese Abfrage zeigt die Syntax für die Verwendung einer JOIN-Anweisung mit dem Hinweis
JOIN_METHOD
zum Auswählen einesHASH JOIN
:GoogleSQL
SELECT * FROM Singers s JOIN@{JOIN_METHOD=HASH_JOIN} Albums AS a ON a.SingerId = a.SingerId
PostgreSQL
SELECT * FROM Singers s JOIN/*@ JOIN_METHOD=HASH_JOIN */ Albums AS a ON a.SingerId = a.SingerId
Wenn Sie einen
HASH JOIN
oderAPPLY JOIN
verwenden und eineWHERE
-Klausel haben, die auf einer Seite IhresJOIN
sehr selektiv ist, legen Sie die Tabelle mit der geringsten Anzahl von Zeilen als erste Tabelle in derFROM
-Klausel des Joins fest. Diese Struktur ist hilfreich, weil Sie derzeit inHASH JOIN
Spanner wählt immer die linke Tabelle als Build in der rechten Tabelle als Sonde. Auf ähnliche Weise wählt Spanner fürAPPLY JOIN
die linke Tabelle als Outer Join und die rechte Tabelle als Inner Join aus. Weitere Informationen zu diesen Join-Typen finden Sie unter Hash Join und Join anwenden.Geben Sie für Abfragen, die für Ihre Arbeitslast kritisch sind, die leistungsstärkste an Join-Methode und Join-Reihenfolge in Ihren SQL-Anweisungen, um eine einheitlichere die Leistung.
Große Lesevorgänge in Lese-Schreib-Transaktionen vermeiden
Lese-Schreib-Transaktionen ermöglichen eine Sequenz von null oder mehr Lesevorgängen oder SQL-Abfragen und können eine Reihe von Mutationen vor einem Aufruf zum Commit enthalten. Um die Konsistenz Ihrer Daten zu gewährleisten, erhält Spanner Sperren beim Lesen und Schreiben von Zeilen in Ihren Tabellen und Indexen. Weitere Informationen zu Sperrungen finden Sie unter Lebensdauer von Lese- und Schreibvorgängen.
Aufgrund der Funktionsweise von Sperren in Spanner ist es erforderlich, einen Lese- oder SQL-Code
Abfrage, die eine große Anzahl von Zeilen liest (z. B. SELECT * FROM Singers
)
bedeutet, dass keine anderen Transaktionen in die Zeilen schreiben können, die Sie gelesen haben,
Ihre Transaktion wurde entweder festgeschrieben oder abgebrochen.
Da Ihre Transaktion eine große Anzahl von Zeilen verarbeitet, dauert sie wahrscheinlich länger als eine Transaktion, die einen kleinen Zeilenbereich liest (z. B.SELECT LastName FROM Singers WHERE SingerId = 7
). Dadurch wird das Problem weiter verschärft und der Systemdurchsatz reduziert.
Daher sollten Sie große Lesevorgänge (z. B. vollständige Tabellenscans oder massive Verknüpfungsvorgänge) in Ihren Transaktionen vermeiden, es sei denn, Sie sind bereit, einen niedrigeren Schreibdurchsatz zu akzeptieren.
In einigen Fällen kann das folgende Muster bessere Ergebnisse liefern:
- Führen Sie Ihre großen Lesevorgänge in einer schreibgeschützten Transaktion aus. Schreibgeschützte Transaktionen ermöglichen einen höheren Gesamtdurchsatz, keine Schlösser verwenden.
- Optional: Führen Sie eine Verarbeitung der gerade gelesenen Daten durch.
- Starten Sie eine Lese-Schreib-Transaktion.
- Prüfen Sie, ob sich die Werte der wichtigen Zeilen nicht geändert haben, seit Sie die schreibgeschützte Transaktion in Schritt 1 ausgeführt haben.
- Wenn sich die Zeilen geändert haben, führen Sie einen Rollback der Transaktion durch und beginnen Sie noch einmal bei Schritt 1.
- Wenn alles in Ordnung ist, können Sie einen Commit Ihrer Mutationen durchführen.
Sie können große Lesevorgänge in Lese-Schreib-Transaktionen vermeiden, wenn Sie sich die Ausführungspläne ansehen, die von Ihren Abfragen generiert werden.
Verwenden Sie ORDER BY, um die Reihenfolge Ihrer SQL-Ergebnisse sicherzustellen
Wenn Sie eine bestimmte Reihenfolge für die Ergebnisse einer SELECT
-Abfrage erwarten, sollten Sie die ORDER BY
-Klausel explizit einschließen. Wenn Sie zum Beispiel
alle Sänger in Primärschlüsselreihenfolge auflisten, verwenden Sie diese Abfrage:
SELECT * FROM Singers
ORDER BY SingerId;
Spanner garantiert nur die Ergebnisreihenfolge, wenn die ORDER BY
-Klausel in der Abfrage vorhanden ist. Mit anderen Worten, betrachten Sie diese Abfrage ohne ORDER
BY
:
SELECT * FROM Singers;
Spanner garantiert nicht, dass die Ergebnisse dieser Abfrage in
Primärschlüsselreihenfolge. Außerdem kann sich die Reihenfolge der Ergebnisse jederzeit ändern.
und ist nicht zwangsläufig von Aufruf zu Aufruf konsistent. Wenn eine Abfrage
eine ORDER BY
-Klausel hat und Spanner einen Index verwendet, der die
erforderlich, dann sortiert Spanner die Daten nicht explizit. Sie müssen sich also keine Gedanken über die Auswirkungen auf die Leistung machen. Sie können die
ob ein expliziter Sortiervorgang in der Ausführung enthalten ist,
Abfrageplan.
STARTS_WITH anstelle von LIKE verwenden
Weil Spanner parametrisierte LIKE
-Muster erst dann auswertet
Ausführungszeit müssen, muss Spanner alle Zeilen lesen und anhand der
Ausdruck LIKE
, um nicht übereinstimmende Zeilen herauszufiltern.
Wenn ein LIKE
-Muster das Format foo%
hat (z. B. wenn es mit einer festen
String und endet mit einem einzelnen Platzhalterprozentsatz) und die Spalte ist indexiert. Verwenden Sie
STARTS_WITH
statt LIKE
. Mit dieser Option kann Spanner den Abfrageausführungsplan effektiver optimieren.
Nicht empfohlen:
GoogleSQL
SELECT a.AlbumTitle FROM Albums a WHERE a.AlbumTitle LIKE @like_clause;
PostgreSQL
SELECT a.AlbumTitle FROM Albums a WHERE a.AlbumTitle LIKE $1;
Empfohlen:
GoogleSQL
SELECT a.AlbumTitle FROM Albums a WHERE STARTS_WITH(a.AlbumTitle, @prefix);
PostgreSQL
SELECT a.AlbumTitle FROM Albums a WHERE STARTS_WITH(a.AlbumTitle, $2);
Commit-Zeitstempel verwenden
Wenn Ihre Anwendung Daten abfragen muss, die nach einem bestimmten Zeitpunkt geschrieben wurden, fügen Sie den entsprechenden Tabellen Spalten mit Commit-Zeitstempeln hinzu. Commit-Zeitstempel
eine Spanner-Optimierung ermöglichen, die den E/A-
Abfragen, deren WHERE
-Klauseln die Ergebnisse auf kürzlich geschriebene Zeilen beschränken
als eine bestimmte Zeit.
Weitere Informationen zu dieser Optimierung erhalten Sie mit GoogleSQL-Dialekt-Datenbanken oder mit PostgreSQL-Dialekt-Datenbanken