Statistiken sperren

Spanner bietet Sperrstatistiken, mit denen Sie die Zeilenschlüssel- und Tabellenspalten identifizieren können, die während eines bestimmten Zeitraums die Hauptquellen für Transaktionssperrkonflikte 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 jeweils 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 zur Gesamtwartezeit bei Sperren eines bestimmten Zeilenschlü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 bei Sperren während des angegebenen Intervalls.

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 beispielhaften Sperranfrage, die zum Sperrenkonflikt beigetragen hat, indem entweder auf eine Sperre gewartet oder andere Transaktionen für den jeweiligen Zeilenschlüssel (Bereich) daran gehindert werden, die Sperre 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 und 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 erhalten 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 es anderen Lesevorgängen ermöglicht, weiterhin auf die Daten zuzugreifen, bis die Transaktion für den Commit bereit ist. Diese gemeinsame Sperre wird übernommen, wenn eine Lese-Schreib-Transaktion Daten liest.

  • WriterShared-Sperre: Diese Sperre wird übernommen, wenn eine Lese-/Schreibtransaktion versucht, einen Commit mitzuschreiben.

  • Exclusive-Sperre: Eine exklusive Sperre wird gewährt, wenn eine Lese-/Schreibtransaktion, die bereits eine ReaderShared-Sperre erhalten hat, nach dem Lesen versucht, Daten zu schreiben. Eine exklusive Sperre ist ein Upgrade einer ReaderShared-Sperre. Eine exklusive Sperre ist ein Sonderfall einer Transaktion, die gleichzeitig die ReaderShared- und die WriterShared-Sperre enthält. Keine andere Transaktion kann eine Sperre für dieselbe Zelle erhalten.

  • WriterSharedTimestamp-Sperre: eine spezielle Art von WriterShared-Sperre, die beim Einfügen neuer Zeilen in eine Tabelle mit einem Commit-Zeitstempel als Teil des Primärschlüssels erlangt wird. Diese Art der Sperre verhindert, dass Transaktionsteilnehmer genau dieselbe Zeile erstellen und somit in Konflikt stehen. Spanner aktualisiert den Schlüssel der eingefügten Zeile so, dass 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 Ja Ja Ja
WriterShared Ja Nein Ja Nicht zutreffend
Exclusive Ja Ja Ja Nicht zutreffend
WriterSharedTimestamp Ja Nicht zutreffend Nicht zutreffend Ja

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 werden in Intervallen von einer Minute gewartet.

  • 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 jeweils 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 von Sperren für die 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. Die exponierten Messwerte sind:

    • 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.

Fehlerbehebung bei Sperrkonflikten in Ihrer Datenbank mithilfe von Sperrstatistiken

Mit SQL oder dem Dashboard Lock Insights können Sie Sperrkonflikte in Ihrer Datenbank ansehen.

In den folgenden Abschnitten wird gezeigt, wie Sie solche Sperrkonflikte mithilfe von SQL-Code untersuchen können.

Zeitraum für die Untersuchung auswählen

Sie prüfen die Latenzmesswerte für Ihre Spanner-Datenbank und ermitteln einen Zeitraum, in dem Ihre Anwendung eine hohe Latenz und CPU-Nutzung aufweist. Beispiel: Das Problem trat am 12. November 2020 gegen 22:50 Uhr auf.

Ermitteln, ob die Latenz des Commits für Transaktionen im ausgewählten Zeitraum zusammen mit der Wartezeit bei Sperren zugenommen hat

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 wir als Beispiel die folgenden Ergebnisse zu unserer Abfrage:

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 Ergebnisse zeigen einen starken Anstieg bei avg_commit_latency_seconds und total_lock_wait_seconds im selben Zeitraum vom 12.11.2020 bis zum 12.11.2020. Danach sind die Werte wieder gesunken. Beachten Sie, dass avg_commit_latency_seconds die durchschnittliche Zeit ist, die nur für den Commit-Schritt aufgewendet wird. 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 nun bestätigt haben, dass die Wartezeit bei Sperren eng mit der erhöhten Schreiblatenz zusammenhängt, werden wir im nächsten Schritt untersuchen, welche Zeilen und Spalten die lange Wartezeit verursachen.

Ermitteln, bei welchen Zeilenschlüsseln und Spalten im ausgewählten Zeitraum lange Wartezeiten bei Sperren hatten

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. 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, in der die Transaktionen um die Sperre konkurrieren. Daher identifizieren wir im nächsten Schritt die Transaktionen, 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 auftreten, 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 wurden:

  • Transaktionen, die beim Versuch, die ReaderShared-Sperre abzurufen, eine Spalte lesen, die einen Sperrkonflikt verursacht hat.

  • Transaktionen, die in eine Spalte schreiben, die beim Versuch, eine WriterShared-Sperre abzurufen, zu einem Sperrkonflikt geführt hat.

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 Sie die Transaktion mit der höchsten Commit-Latenz zuerst sehen.

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, bei der während des Zeitraums Sperrkonflikte aufgetreten sind. Nachdem Sie die Transaktionen identifiziert haben, die die Sperrkonflikte verursachen, können Sie die Transaktionen mit ihrem Fingerabdruck fprint analysieren, um potenzielle Probleme zu identifizieren, die zum Sperrkonflikt beigetragen haben.

Nachdem Sie die Transaktion mit fprint=1866043996151916800 überprüft haben, können Sie mithilfe der 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 aufrufen, 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 lösen Sie den Sperrkonflikt:

  1. Verwenden Sie eine schreibgeschützte Transaktion, um die erforderlichen SingerId-Werte zu ermitteln.
  2. Verwenden Sie eine separate Lese-/Schreibtransaktion, um die Zeilen für die erforderlichen SingerId-Werte zu aktualisieren.

Best Practices zur Reduzierung von Konflikten durch Sperren anwenden

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 bald wie möglich nach dem Lesen der Daten in einer Lese-Schreib-Transaktion per Commit durchführen. Mit einer Lese-Schreib-Transaktion wird sichergestellt, dass die Daten nach dem Lesen unverändert bleiben, bis die Änderung erfolgreich per Commit übertragen wurde. Dazu müssen die Datenzellen während des Lesevorgangs und des Commits für die Transaktion gesperrt werden. 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. Bei einer lang andauernden Transaktion ist eine Sperre über einen langen Zeitraum erforderlich. Daher sollten Sie eine Transaktion, die Tausende von Zeilen betrifft, 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 also die Lese-/Schreibtransaktion keine Daten liest, müssen die Zellen nicht lange gesperrt werden.

  • Geben Sie nur den minimalen Satz von Spalten an, der für eine Lese-/Schreibtransaktion erforderlich ist. Da Spanner-Sperren pro Datenzelle erfolgen, wird eine ReaderShared-Sperre für diese Zellen übernommen, wenn eine Lese-Schreib-Transaktion sehr viele Spalten liest. Dies kann zu Sperrenkonflikten führen, wenn andere Transaktionen eine WriterShared-Sperre für Schreibvorgänge in die übermäßig vielen Spalten erhalten. Sie können beispielsweise beim Lesen einen Satz von Spalten anstelle von * angeben.

  • Minimieren Sie API-Aufrufe in einer Lese-/Schreibtransaktion. Die Latenz von API-Aufrufen kann zu Sperrenkonflikten in Spanner führen, da API-Aufrufe Netzwerkverzögerungen sowie dienstseitigen Verzögerungen unterliegen. Wir empfehlen, API-Aufrufe nach Möglichkeit außerhalb von Lese-/Schreibtransaktionen auszuführen. Wenn Sie API-Aufrufe innerhalb einer Lese-Schreib-Transaktion ausführen müssen, müssen Sie die Latenz der API-Aufrufe überwachen, um die Auswirkungen auf den Erwerbszeitraum für die Sperre zu minimieren.

  • Orientieren Sie sich an den Best Practices für Schemadesign.

Nächste Schritte