Spanner bietet Sperrstatistiken, mit denen Sie den Zeilenschlüssel und die Tabellenspalten identifizieren können, die während eines bestimmten Zeitraums die Hauptursachen für Konflikte mit Transaktionssperren in Ihrer Datenbank waren. Sie können diese Statistiken mithilfe von SQL-Anweisungen aus den SPANNER_SYS.LOCK_STATS*
-Systemtabellen abrufen.
Verfügbarkeit
SPANNER_SYS
-Daten sind nur über SQL-Schnittstellen verfügbar. Beispiel:
Die Spanner Studio-Seite einer Datenbank in der Google Cloud Console
Das Dashboard Lock Insights
Mit der
executeQuery
API
Andere von Spanner bereitgestellte Methoden für einzelne Leseaufrufe unterstützen SPANNER_SYS
nicht.
Statistiken nach Zeilenschlüssel sperren
In den folgenden Tabellen wird der Zeilenschlüssel mit der höchsten Wartezeit nachverfolgt:
SPANNER_SYS.LOCK_STATS_TOP_MINUTE
: Zeilenschlüssel mit den höchsten Wartezeiten bei Sperren in Intervallen von 1 Minute.SPANNER_SYS.LOCK_STATS_TOP_10MINUTE
: Zeilenschlüssel mit der höchsten Sperrwartezeit in 10-Minuten-Intervallen.SPANNER_SYS.LOCK_STATS_TOP_HOUR
: Zeilenschlüssel mit der Sperrwartezeit in 1-Stunden-Intervallen.
Diese Tabellen haben folgende Attribute:
Jede Tabelle enthält Daten für nicht überlappende Zeitintervalle in der Länge, die der Tabellenname angibt.
Die Intervalle basieren auf der Uhrzeit. 1-Minuten-Intervalle enden zur vollen Minute, 10-Minuten-Intervalle enden alle 10 Minuten ab der vollen Stunde und 1-Stunden-Intervalle enden zur vollen Stunde. Nach jedem Intervall erfasst Spanner Daten von allen Servern und stellt die Daten kurz danach in den SPANNER_SYS-Tabellen zur Verfügung.
Beispielsweise sind die neuesten, für SQL-Abfragen verfügbaren Intervalle um 11:59:30 Uhr:
- 1 Minute: 11:58:00–11:58:59 Uhr
- 10 Minuten: 11:40:00–11:49:59 Uhr
- 1 Stunde: 10:00:00–10:59:59 Uhr
Spanner gruppiert die Statistiken, indem der Zeilenschlüsselbereich gestartet wird.
Jede Zeile enthält Statistiken für die Gesamtwartezeit bei der Sperrung eines bestimmten Startzeilenschlüsselbereichs, für den Spanner während des angegebenen Intervalls Statistiken erfasst.
Wenn Spanner nicht in der Lage ist, Informationen zu jedem Zeilenschlüsselbereich für Sperrwartezeiten während des Intervalls zu speichern, priorisiert das System den Zeilenschlüsselbereich mit der höchsten Wartezeit für Sperren während des angegebenen Intervalls.
Für alle Spalten in den Tabellen sind Nullwerte zulässig.
Tabellenschema
Spaltenname | Typ | Beschreibung |
---|---|---|
INTERVAL_END |
TIMESTAMP |
Ende des Zeitintervalls, in dem die enthaltenen Sperrkonflikte aufgetreten sind. |
ROW_RANGE_START_KEY |
BYTES(MAX) |
Der Zeilenschlüssel, in dem der Sperrkonflikt aufgetreten ist. Wenn der Konflikt einen Bereich von Zeilen beinhaltet, stellt dieser Wert den Startschlüssel dieses Bereichs dar. Ein Pluszeichen, + , bezeichnet einen Bereich.
Weitere Informationen finden Sie unter Was ist ein Startschlüssel für einen Zeilenbereich?.
|
LOCK_WAIT_SECONDS |
FLOAT64 |
Die kumulative Wartezeit der Sperre von Sperrkonflikten, die für alle Spalten im Zeilenschlüsselbereich aufgezeichnet wurden, in Sekunden. |
SAMPLE_LOCK_REQUESTS |
ARRAY<STRUCT<
|
Jeder Eintrag in diesem Array entspricht einer Beispiel-Sperranfrage, die zu dem Sperrkonflikt beigetragen hat, indem entweder auf eine Sperre gewartet oder andere Transaktionen daran gehindert wurden, die Sperre für den angegebenen Zeilenschlüssel (Bereich) zu übernehmen. Die maximale Anzahl von Stichproben in diesem Array beträgt 20.
Jedes Beispiel enthält die folgenden drei Felder:
|
Sperrmodi
Spanner-Vorgänge erhalten Sperren, wenn die Vorgänge Teil einer Lese-Schreib-Transaktion sind. Schreibgeschützte Transaktionen erlangen keine Sperren. Spanner verwendet verschiedene Sperrmodi, um die Anzahl der Transaktionen zu maximieren, die zu einem bestimmten Zeitpunkt Zugriff auf eine bestimmte Datenzelle haben. Unterschiedliche Sperren haben unterschiedliche Eigenschaften. Beispielsweise können einige Sperren von mehreren Transaktionen gemeinsam genutzt werden, andere hingegen nicht.
Ein Sperrkonflikt kann auftreten, wenn Sie versuchen, einen der folgenden Sperrmodi in einer Transaktion abzurufen.
ReaderShared
-Sperre: Eine Sperre, die anderen Lesevorgängen ermöglicht, so lange auf die Daten zuzugreifen, bis die Transaktion zum Commit bereit ist. Diese gemeinsame Sperre wird erhalten, wenn eine Lese-Schreib-Transaktion Daten liest.WriterShared
-Sperre: Diese Sperre wird erhalten, wenn eine Lese-Schreib-Transaktion versucht, einen Schreibvorgang festzuschreiben.Exclusive
-Sperre: Eine exklusive Sperre wird erhalten, wenn eine Lese-Schreib-Transaktion, die bereits eine ReaderShared-Sperre erhalten hat, versucht, Daten nach Abschluss des Lesevorgangs zu schreiben. Eine exklusive Sperre ist ein Upgrade von einerReaderShared
-Sperre. Eine exklusive Sperre ist ein Sonderfall einer Transaktion, die die SperreReaderShared
undWriterShared
gleichzeitig enthält. Keine andere Transaktion kann eine Sperre für dieselbe Zelle abrufen.WriterSharedTimestamp
-Sperre: Eine spezielleWriterShared
-Sperre, die beim Einfügen neuer Zeilen in eine Tabelle übernommen wird, deren Primärschlüssel Commit-Zeitstempel ist. Diese Art der Sperre verhindert, dass Transaktionsteilnehmer dieselbe Zeile erstellen und dadurch miteinander in Konflikt stehen. Spanner aktualisiert den Schlüssel der eingefügten Zeile, damit er mit dem Commit-Zeitstempel der Transaktion übereinstimmt, die die Einfügung ausgeführt hat.
Weitere Informationen zu Transaktionstypen und den verfügbaren Sperren finden Sie unter Transaktionen.
Konflikte mit Sperrmodus
Die folgende Tabelle zeigt die möglichen Konflikte zwischen verschiedenen Sperrmodi.
Sperrmodi | ReaderShared |
WriterShared |
Exclusive |
WriterSharedTimestamp |
---|---|---|---|---|
ReaderShared |
Nein | Yes | Yes | Yes |
WriterShared |
Yes | Nein | Yes | Nicht zutreffend |
Exclusive |
Yes | Yes | Yes | Nicht zutreffend |
WriterSharedTimestamp |
Yes | Nicht zutreffend | Nicht zutreffend | Yes |
WriterSharedTimestamp
-Sperren werden nur verwendet, wenn neue Zeilen mit einem Zeitstempel als Teil des Primärschlüssels eingefügt werden. Die Sperren WriterShared
und Exclusive
werden verwendet, wenn in vorhandene Zellen geschrieben oder neue Zeilen ohne Zeitstempel eingefügt werden. Daher kann WriterSharedTimestamp
nicht mit anderen Arten von Sperren in Konflikt stehen und diese Szenarien werden in der obigen Tabelle als Nicht zutreffend angezeigt.
Die einzige Ausnahme ist ReaderShared
, das auf nicht vorhandene Zeilen angewendet werden kann und daher mit WriterSharedTimestamp
in Konflikt stehen kann. Beispiel: Ein vollständiger Tabellenscan sperrt die gesamte Tabelle auch für Zeilen, die noch nicht erstellt wurden. Daher kann ReaderShared
mit WriterSharedTimestamp
in Konflikt stehen.
Was ist ein Startschlüssel für einen Zeilenbereich?
Die Spalte ROW_RANGE_START_KEY
gibt den zusammengesetzten Primärschlüssel an oder beginnt den Primärschlüssel eines Zeilenbereichs mit Sperrenkonflikten. Das folgende Schema dient zur Veranschaulichung eines Beispiels.
CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo BYTES(MAX),
) PRIMARY KEY (SingerId);
CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE;
CREATE TABLE Songs (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
TrackId INT64 NOT NULL,
SongName STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId, TrackId),
INTERLEAVE IN PARENT Albums ON DELETE CASCADE;
CREATE TABLE Users (
UserId INT64 NOT NULL,
LastAccess TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true),
...
) PRIMARY KEY (UserId, LastAccess);
Wie die folgende Tabelle mit den Zeilenschlüsseln und Zeilenschlüsselbereichen zeigt, wird ein Bereich durch das Pluszeichen "+" angezeigt. Der Schlüssel in diesen Fällen stellt den Startschlüssel eines Schlüsselbereichs dar, in dem ein Sperrkonflikt aufgetreten ist.
ROW_RANGE_START_KEY | Erklärung |
---|---|
Singers(2) | Tabelle "Singers" bei Schlüssel "SingerId=2" |
Alben(2,1) | Album-Tabelle bei Schlüssel SingerId=2,AlbumId=1 |
Songs(2,1,5) | Tabelle "Songs" unter dem Schlüssel "SingerId=2,AlbumId=1,TrackId=5" |
Songs(2,1,5+) | Schlüsselbereich der Songstabelle, beginnend bei SingerId=2,AlbumId=1,TrackId=5 |
Alben(2,1+) | Album-Tabellenschlüsselbereich ab SingerId=2,AlbumId=1 |
Nutzer(3, 2020-11-01 12:34:56.426426+00:00) | Nutzertabelle bei Schlüssel "UserId=3, LastAccess=commit_timestamp" |
Zusammengefasste Statistiken
SPANNER_SYS
enthält auch Tabellen zum Speichern aggregierter Daten für Sperrstatistiken, die von Spanner in einem bestimmten Zeitraum erfasst wurden:
SPANNER_SYS.LOCK_STATS_TOTAL_MINUTE
: Aggregierte Statistiken für alle Sperren warten in Intervallen von 1 Minute.SPANNER_SYS.LOCK_STATS_TOTAL_10MINUTE
: Zusammengefasste Statistiken für alle Sperrzeiten in 10-Minuten-IntervallenSPANNER_SYS.LOCK_STATS_TOTAL_HOUR
: Zusammengefasste Statistiken für alle Sperrzeiten in 1-Stunden-Intervallen.
Zusammengefasste Statistiktabellen haben die folgenden Eigenschaften:
Jede Tabelle enthält Daten für nicht überlappende Zeitintervalle in der Länge, die der Tabellenname angibt.
Die Intervalle basieren auf der Uhrzeit. 1-Minuten-Intervalle enden zur vollen Minute, 10-Minuten-Intervalle enden alle 10 Minuten ab der vollen Stunde und 1-Stunden-Intervalle enden zur vollen Stunde.
Zum Beispiel sind um 11:59:30 Uhr die neuesten Intervalle, die für SQL-Abfragen zu zusammengefassten Sperrstatistiken zur Verfügung stehen:
- 1 Minute: 11:58:00–11:58:59 Uhr
- 10 Minuten: 11:40:00–11:49:59 Uhr
- 1 Stunde: 10:00:00–10:59:59 Uhr
Jede Zeile enthält aggregierte Statistiken für alle Wartezeiten in der Datenbank während des angegebenen Intervalls. Es gibt nur je eine Zeile pro Zeitintervall.
Die in den
SPANNER_SYS.LOCK_STATS_TOTAL_*
-Tabellen erfassten Statistiken enthalten Wartezeiten bei Sperren, die Spanner nicht in denSPANNER_SYS.LOCK_STATS_TOP_*
-Tabellen erfasst hat.Einige Spalten in diesen Tabellen werden in Cloud Monitoring als Messwerte angezeigt. Folgende Messwerte stehen zur Verfügung:
- Wartezeit bei Sperren
Weitere Informationen finden Sie unter Spanner-Messwerte.
Tabellenschema
Spaltenname | Typ | Beschreibung |
---|---|---|
INTERVAL_END |
TIMESTAMP |
Ende des Zeitintervalls, in dem der Sperrkonflikt aufgetreten ist. |
TOTAL_LOCK_WAIT_SECONDS |
FLOAT64 |
Gesamtwartezeit für Sperrungen für Sperrkonflikte, die für die gesamte Datenbank aufgezeichnet wurden, in Sekunden. |
Beispielabfragen
Das folgende Beispiel zeigt eine SQL-Anweisung, mit der Sie Sperrstatistiken abrufen können. Sie können diese SQL-Anweisungen mit den Clientbibliotheken, gcloud spanner oder der Google Cloud Console ausführen.
Sperrstatistiken für das vorherige 1-Minuten-Intervall auflisten
Die folgende Abfrage gibt die Informationen zur Sperre für jeden Zeilenschlüssel mit einem Sperrkonflikt zurück, einschließlich des Anteils der Gesamtsperrekonflikte während des letzten 1-Minuten-Zeitintervalls.
Die Funktion CAST()
konvertiert das BYTES-Feld "row_range_start_key" in einen STRING.
SELECT CAST(s.row_range_start_key AS STRING) AS row_range_start_key,
t.total_lock_wait_seconds,
s.lock_wait_seconds,
s.lock_wait_seconds/t.total_lock_wait_seconds frac_of_total,
s.sample_lock_requests
FROM spanner_sys.lock_stats_total_minute t, spanner_sys.lock_stats_top_minute s
WHERE t.interval_end =
(SELECT MAX(interval_end)
FROM spanner_sys.lock_stats_total_minute)
AND s.interval_end = t.interval_end
ORDER BY s.lock_wait_seconds DESC;
Screenshot: Ausgabe der Abfrage
row_range_start_key | total_lock_wait_seconds | lock_wait_seconds | frac_of_total | sample_lock_requests |
---|---|---|---|---|
Songs(2,1,1) | 2,37 | 1,76 | 0,7426 | LOCK_MODE: ReaderShared SPALTE: Singers.SingerInfo LOCK_MODE: WriterShared Spalte: Singers.SingerInfo |
Nutzer(3, 2020-11-01 12:34:56.426426+00:00) | 2,37 | 0,61 | 0,2573 | LOCK_MODE: ReaderShared SPALTE: users._exists1 LOCK_MODE: WriterShared SPALTE: users._exists1 |
1 _exists
ist ein internes Feld, mit dem geprüft wird, ob eine bestimmte Zeile vorhanden ist.
Datenaufbewahrung
Spanner speichert die Daten für jede Tabelle mindestens für die folgenden Zeiträume:
SPANNER_SYS.LOCK_STATS_TOP_MINUTE
undSPANNER_SYS.LOCK_STATS_TOTAL_MINUTE
: Intervalle der letzten 6 Stunden.SPANNER_SYS.LOCK_STATS_TOP_10MINUTE
undSPANNER_SYS.LOCK_STATS_TOTAL_10MINUTE
: Intervalle der letzten 4 Tage.SPANNER_SYS.LOCK_STATS_TOP_HOUR
undSPANNER_SYS.LOCK_STATS_TOTAL_HOUR
: Intervalle der letzten 30 Tage.
Sperrkonflikte in Ihrer Datenbank mithilfe von Sperrstatistiken beheben
Sie können SQL oder das Dashboard Lock Insights verwenden, um Sperrkonflikte in Ihrer Datenbank anzusehen.
In den folgenden Themen wird gezeigt, wie Sie solche Konflikte mit Sperren mithilfe von SQL-Code untersuchen können.
Zu untersuchenden Zeitraum auswählen
Sie untersuchen die Latenzmesswerte für Ihre Spanner-Datenbank und ermitteln einen Zeitraum, in dem Ihre Anwendung eine hohe Latenz und CPU-Auslastung aufweist. Das Problem ist beispielsweise am 12. November 2020 gegen 22:50 Uhr aufgetreten.
Ermitteln, ob die Latenz für den Commit von Transaktionen zusammen mit der Wartezeit für die Sperre während des ausgewählten Zeitraums gestiegen ist
Sperren werden von Transaktionen abgerufen. Wenn Sperrkonflikte lange Wartezeiten verursachen, sollten wir neben der Erhöhung der Wartezeit für die Sperre auch eine Erhöhung der Commit-Latenz der Transaktion erkennen können.
Nachdem ein Zeitraum zum Starten der Prüfung ausgewählt wurde, führen wir die Transaktionsstatistiken TXN_STATS_TOTAL_10MINUTE
mit den Sperrstatistiken LOCK_STATS_TOTAL_10MINUTE
zusammen, um uns bei der Ermittlung zu unterstützen, ob die Erhöhung der durchschnittlichen Commit-Latenz durch die Erhöhung der Wartezeit der Sperre ausgelöst wird.
SELECT t.interval_end, t.avg_commit_latency_seconds, l.total_lock_wait_seconds
FROM spanner_sys.txn_stats_total_10minute t
LEFT JOIN spanner_sys.lock_stats_total_10minute l
ON t.interval_end = l.interval_end
WHERE
t.interval_end >= "2020-11-12T21:50:00Z"
AND t.interval_end <= "2020-11-12T23:50:00Z"
ORDER BY interval_end;
Nehmen Sie die folgenden Daten als Beispiel für die Ergebnisse, die wir von unserer Abfrage erhalten.
interval_end | avg_commit_latency_seconds | total_lock_wait_seconds |
---|---|---|
2020-11-12 21:40:00-07:00 | 0,002 | 0,090 |
2020-11-12 21:50:00-07:00 | 0,003 | 0,110 |
2020-11-12 22:00:00-07:00 | 0,002 | 0,100 |
2020-11-12 22:10:00-07:00 | 0,002 | 0,080 |
2020-11-12 22:20:00-07:00 | 0,030 | 0,240 |
2020-11-12 22:30:00-07:00 | 0,034 | 0,220 |
2020-11-12 22:40:00-07:00 | 0,034 | 0,218 |
2020-11-12 22:50:00-07:00 | 3,741 | 780,193 |
2020-11-12 23:00:00-07:00 | 0,042 | 0,240 |
2020-11-12 23:10:00-07:00 | 0,038 | 0,129 |
2020-11-12 23:20:00-07:00 | 0,021 | 0,128 |
2020-11-12 23:30:00-07:00 | 0,038 | 0,231 |
Diese vorherigen Ergebnisse zeigen einen drastischen Anstieg von avg_commit_latency_seconds
und total_lock_wait_seconds
im selben Zeitraum zwischen 2020-11-12
22:40:00 und 2020-11-12 22:50:00 und sind danach wieder gesunken. Beachten Sie, dass avg_commit_latency_seconds
die durchschnittliche Zeit ist, die nur für den Commit-Schritt aufgewendet wurde. total_lock_wait_seconds
ist jedoch die zusammengefasste Sperrzeit für den Zeitraum, sodass die Zeit viel länger als die Commit-Zeit der Transaktion dauert.
Nachdem wir bestätigt haben, dass die Wartezeit bei Sperren eng mit der erhöhten Schreiblatenz verbunden ist, untersuchen wir im nächsten Schritt, welche Zeilen und Spalten die lange Wartezeit verursachen.
Ermitteln Sie, für welche Zeilenschlüssel und Spalten im ausgewählten Zeitraum lange Wartezeiten aufgrund von Sperren aufgetreten sind
Um herauszufinden, für welche Zeilenschlüssel und Spalten in dem von uns untersuchten Zeitraum die hohen Sperrzeiten aufgetreten sind, fragen wir dieLOCK_STAT_TOP_10MINUTE
Table. Diese Tabelle enthält die Zeilenschlüssel und Spalten, die am meisten zum Sperren warten.
Die Funktion CAST()
in der folgenden Abfrage wandelt das BYTES-Feld "row_range_start_key" in einen STRING um.
SELECT CAST(s.row_range_start_key AS STRING) AS row_range_start_key,
t.total_lock_wait_seconds,
s.lock_wait_seconds,
s.lock_wait_seconds/t.total_lock_wait_seconds frac_of_total,
s.sample_lock_requests
FROM spanner_sys.lock_stats_total_10minute t, spanner_sys.lock_stats_top_10minute s
WHERE
t.interval_end = "2020-11-12T22:50:00Z" and s.interval_end = t.interval_end;
row_range_start_key | total_lock_wait_seconds | lock_wait_seconds | frac_of_total | sample_lock_requests |
---|---|---|---|---|
Singers(32) | 780,193 | 780,193 | 1 | LOCK_MODE: WriterShared SPALTE: Singers.SingerInfo LOCK_MODE: ReaderShared SPALTE: Singers.SingerInfo |
In dieser Ergebnistabelle sehen Sie, dass der Konflikt in der Tabelle Singers
unter dem Schlüssel SingerId=32 aufgetreten ist. Die Singers.SingerInfo
ist die Spalte, in der der Sperrkonflikt zwischen ReaderShared
und WriterShared
aufgetreten ist.
Dies ist ein häufiger Konflikttyp, wenn eine Transaktion versuchen, eine bestimmte Zelle zu lesen, und die andere Transaktion versucht, in dieselbe Zelle zu schreiben. Wir kennen jetzt die genaue Datenzelle, um die die Transaktionen die Sperre konkurrieren, sodass wir im nächsten Schritt die Transaktionen identifizieren, die um die Sperren konkurrieren.
Ermitteln, welche Transaktionen auf die Spalten zugreifen, die am Sperrkonflikt beteiligt sind
Wenn Sie die Transaktionen ermitteln möchten, bei denen innerhalb eines bestimmten Zeitintervalls aufgrund von Sperrkonflikten eine erhebliche Commit-Latenz festgestellt wird, müssen Sie die folgenden Spalten aus der Tabelle SPANNER_SYS.TXN_STATS_TOTAL_10MINUTE
abfragen:
fprint
read_columns
write_constructive_columns
avg_commit_latency_seconds
Sie müssen nach gesperrten Spalten filtern, die in der Tabelle SPANNER_SYS.LOCK_STATS_TOP_10MINUTE
identifiziert werden:
Transaktionen, die beim Versuch, die
ReaderShared
-Sperre zu erhalten, eine Spalte lesen, die zu einem Sperrkonflikt geführt hat.Transaktionen, die in eine beliebige Spalte schreiben, die beim Versuch, eine
WriterShared
-Sperre zu erhalten, zu einem Sperrkonflikt geführt haben.
SELECT
fprint,
read_columns,
write_constructive_columns,
avg_commit_latency_seconds
FROM spanner_sys.txn_stats_top_10minute t2
WHERE (
EXISTS (
SELECT * FROM t2.read_columns columns WHERE columns IN (
SELECT DISTINCT(req.COLUMN)
FROM spanner_sys.lock_stats_top_10minute t, t.SAMPLE_LOCK_REQUESTS req
WHERE req.LOCK_MODE = "ReaderShared" AND t.interval_end ="2020-11-12T23:50:00Z"))
OR
EXISTS (
SELECT * FROM t2.write_constructive_columns columns WHERE columns IN (
SELECT DISTINCT(req.COLUMN)
FROM spanner_sys.lock_stats_top_10minute t, t.SAMPLE_LOCK_REQUESTS req
WHERE req.LOCK_MODE = "WriterShared" AND t.interval_end ="2020-11-12T23:50:00Z"))
)
AND t2.interval_end ="2020-11-12T23:50:00Z"
ORDER BY avg_commit_latency_seconds DESC;
Das Abfrageergebnis wird nach der Spalte avg_commit_latency_seconds
sortiert, sodass die Transaktion die höchste Commit-Latenz zuerst aufweist.
fprint | read_columns | write_constructive_columns | avg_commit_latency_seconds |
---|---|---|---|
1866043996151916800 |
['Singers.SingerInfo', 'Singers.FirstName', 'Singers.LastName', 'Singers._exists'] |
['Singers.SingerInfo'] | 4,89 |
4168578515815911936 | [] | ['Singers.SingerInfo'] | 3,65 |
Die Abfrageergebnisse zeigen, dass zwei Transaktionen versucht haben, auf die Spalte Singers.SingerInfo
zuzugreifen. Dies ist die Spalte mit Sperrkonflikten während des Zeitraums.
Nachdem Sie die Transaktionen ermittelt haben, die die Sperrkonflikte verursachen, können Sie die Transaktionen mithilfe ihres Fingerabdrucks fprint
analysieren, um potenzielle Probleme zu identifizieren, die zum Sperrkonflikt geführt haben.
Nachdem Sie die Transaktion mit fprint=1866043996151916800 überprüft haben, können Sie mit den Spalten read_columns
und write_constructive_columns
feststellen, welcher Teil Ihres Anwendungscodes die Transaktion ausgelöst hat. Sie können dann die zugrunde liegende DML ansehen, die nicht nach dem Primärschlüssel SingerId
filtert. Dies führte zu einem vollständigen Tabellenscan und sperrte die Tabelle, bis der Commit der Transaktion durchgeführt wurde.
So beheben Sie den Sperrkonflikt:
- Verwenden Sie eine schreibgeschützte Transaktion, um die erforderlichen
SingerId
-Werte zu identifizieren. - Verwenden Sie eine separate Lese-Schreib-Transaktion, um die Zeilen für die erforderlichen
SingerId
-Werte zu aktualisieren.
Best Practices anwenden, um Konflikte durch Sperren zu reduzieren
In unserem Beispielszenario konnten wir Sperrstatistiken und Transaktionsstatistiken verwenden, um unser Problem auf eine Transaktion einzugrenzen, die nicht den Primärschlüssel unserer Tabelle bei Aktualisierungen verwendet hat. Wir haben Ideen zur Verbesserung der Transaktion entwickelt, die darauf basiert, ob wir die Schlüssel der Zeilen, die wir aktualisieren möchten, schon vorher kennen konnten.
Beachten Sie diese Best Practices, um die Anzahl von Sperrkonflikten in Ihrer Datenbank zu reduzieren, wenn Sie potenzielle Probleme in Ihrer Lösung betrachten oder auch beim Entwerfen Ihrer Lösung.
Verwenden Sie nach Möglichkeit schreibgeschützte Transaktionen, da diese keine Sperren erhalten.
Vermeiden Sie vollständige Tabellenscans in einer Lese-Schreib-Transaktion. Dazu gehört das Schreiben einer DML-Bedingung für den Primärschlüssel oder die Zuweisung eines bestimmten Schlüsselbereichs bei Verwendung der Lese-API.
Halten Sie die Sperrzeit kurz, indem Sie die Änderung so schnell wie möglich nach dem Lesen der Daten in einer Lese-Schreib-Transaktion in einem Commit durchführen. Eine Lese-Schreib-Transaktion gewährleistet, dass die Daten nach dem Lesen der Daten unverändert bleiben, bis Sie die Änderung erfolgreich per Commit übergeben. Dazu muss die Transaktion die Datenzellen während des Lesevorgangs und des Commits sperren. Wenn Sie den Sperrzeitraum kurz halten, ist die Wahrscheinlichkeit von Sperrkonflikten bei Transaktionen geringer.
Bevorzugen Sie kleine Transaktionen gegenüber großen Transaktionen oder partitionierte DML für lang andauernde DML-Transaktionen. Eine lang andauernde Transaktion erhält eine Sperre für einen langen Zeitraum. Daher sollten Sie eine Transaktion, die Tausende von Zeilen berührt, in mehrere kleinere Transaktionen aufteilen, die nach Möglichkeit Hunderte von Zeilen aktualisieren.
Wenn Sie die von einer Lese-Schreib-Transaktion bereitgestellte Garantie nicht benötigen, sollten Sie vor dem Commit der Änderung keine Daten in der Lese-Schreib-Transaktion lesen, z. B. durch Lesen der Daten in einer separaten schreibgeschützten Transaktion. Die meisten Sperrkonflikte treten aufgrund der starken Garantie auf, um sicherzustellen, dass die Daten zwischen dem Lese- und Commit unverändert bleiben. Wenn die Lese-Schreib-Transaktion also keine Daten liest, müssen die Zellen nicht lange gesperrt werden.
Geben Sie nur den minimalen Satz von Spalten an, der in einer Lese-Schreib-Transaktion erforderlich ist. Da Spanner-Sperren pro Datenzelle gelten, erhält eine Lese-Schreib-Transaktion, die übermäßig viele Spalten liest, eine
ReaderShared
-Sperre für diese Zellen. Dies kann zu Sperrkonflikten führen, wenn andere Transaktionen eineWriterShared
-Sperre für Schreibvorgänge in die überzähligen Spalten erhalten. Sie haben beispielsweise die Möglichkeit, beim Lesen einen Satz von Spalten anstelle von*
anzugeben.Minimieren Sie API-Aufrufe in einer Lese-Schreib-Transaktion. Die Latenz von API-Aufrufen kann zu Sperrenkonflikten in Spanner führen, da API-Aufrufe Netzwerk- und dienstseitigen Verzögerungen unterliegen. Wir empfehlen, API-Aufrufe nach Möglichkeit außerhalb von Lese-Schreib-Transaktionen auszuführen. Wenn Sie API-Aufrufe innerhalb einer Lese-Schreib-Transaktion ausführen müssen, müssen Sie die Latenz Ihrer API-Aufrufe überwachen, um die Auswirkungen auf den Zeitraum der Sperre zu minimieren.
Orientieren Sie sich an den Best Practices für Schemadesign.
Nächste Schritte
- Weitere Informationen zu Tools zur Selbstbeobachtung
- Weitere Informationen, die Spanner für jede Datenbank speichert, finden Sie in der Informationsschematabelle für Datenbanken.
- Weitere Informationen zu Best Practices für SQL für Spanner.