Statistiken sperren

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:

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<
  column STRING,
  lock_mode STRING,
   transaction_tag STRING>>
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:
  • lock_mode: Der angeforderte Sperrmodus. Weitere Informationen finden Sie unter Sperrmodi .
  • column: Die Spalte, in der der Sperrkonflikt aufgetreten ist. Das Format dieses Werts ist tablename.columnname.
  • transaction_tag: Das Tag der Transaktion, die die Anfrage gesendet hat. Weitere Informationen zur Verwendung von Tags finden Sie unter Fehlerbehebung mit Transaktions-Tags.
Alle Sperranfragen, die zu Sperrkonflikten beigetragen haben, werden einheitlich nach dem Zufallsprinzip erfasst. Daher ist es möglich, dass nur die Hälfte eines Konflikts (entweder der Inhaber oder der Waiter) in diesem Array aufgezeichnet wird.

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 einer ReaderShared-Sperre. Eine exklusive Sperre ist ein Sonderfall einer Transaktion, die die Sperre ReaderShared und WriterShared gleichzeitig enthält. Keine andere Transaktion kann eine Sperre für dieselbe Zelle abrufen.

  • WriterSharedTimestamp-Sperre: Eine spezielle WriterShared-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-Intervallen

  • SPANNER_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 den SPANNER_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 und SPANNER_SYS.LOCK_STATS_TOTAL_MINUTE: Intervalle der letzten 6 Stunden.

  • SPANNER_SYS.LOCK_STATS_TOP_10MINUTE und SPANNER_SYS.LOCK_STATS_TOTAL_10MINUTE: Intervalle der letzten 4 Tage.

  • SPANNER_SYS.LOCK_STATS_TOP_HOUR und SPANNER_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:

  1. Verwenden Sie eine schreibgeschützte Transaktion, um die erforderlichen SingerId-Werte zu identifizieren.
  2. 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.

  • Große Lesevorgänge in Lese-Schreib-Transaktionen vermeiden.

  • 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 eine WriterShared-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