So verhindern Sie, dass Abfragen auf die Sperre auf Tabellenebene warten

10

Wir haben ein Problem festgestellt, nachdem wir die Datenbank unseres Kunden auf einen zusätzlichen Server verschoben haben. Dies hätte sich positiv auf die Leistung der Site auswirken sollen, es gibt jedoch ein Problem mit der Tabellensperre in MyISAM. (Ich habe von der Verwendung von InnoDB anstelle von MyISAM gehört, aber wir können den Motor in naher Zukunft nicht ändern.)
Wir könnten es an einer Update-Abfrage erkennen, die ausgeführt wird, wenn ein Moderator einen Kommentar auf der Artikelseite aktiviert. Dies ist der Prozess:

  • Update-Abfrage wird verarbeitet SET status = 1 WHERE id = 5(Index wird gesetzt)
  • Die zwischengespeicherten Dateien der Seite werden gelöscht

Zu diesem Zeitpunkt wird die gesamte Seite langsam. Die Datenbank selbst ist minutenlang ausgelastet. Ich habe die Prozessliste einige Male abgerufen und ungefähr 60 Einträge verschiedener Auswahlabfragen gesehen, die sich alle im Status befanden und auf die Sperre auf Tabellenebene warteten .

1. Ich verstehe nicht, warum dieses Update für die Tabelle article_commentsdie select-Anweisungen für die Tabelle beeinflussen kann, um auf die articleSperre auf Tabellenebene zu warten. In der Prozessliste stammten fast alle wartenden Abfragen aus dieser Tabelle. Ich habe über die Tatsache gelesen, dass Aktualisierungen / Einfügungen gegenüber Auswahlen bevorzugt werden und dass dies solche Probleme verursachen kann, aber die Artikeltabelle selbst wird nicht aktualisiert, wenn Kommentare aktiviert werden, sodass die Auswahl nicht warten sollte. Habe ich das falsch verstanden?
2. Gibt es etwas anderes als die Umstellung auf InnoDB, um dieses Verhalten zu verhindern oder zumindest ein besseres Gleichgewicht zu erreichen? Ich bin sehr irritiert über die Tatsache, dass dieses Problem nicht aufgetreten ist, bevor die Datenbank auf den neuen Server verschoben wurde. Ich denke, es gibt einige Fehlkonfigurationen, aber ich weiß nicht, wie ich sie identifizieren soll.

32bitfloat
quelle
1
Aktivieren Sie die allgemeine Protokollierung und achten Sie auf JOIN-Anweisungen zwischen diesen Tabellen. Wenn Sie SELECT auswählen, wird ein implizites READ LOCK erstellt. Da MYISAM das Sperren von ROW LEVEL nicht unterstützt, wird es auf Tabellenebene gesperrt. Es ist wahrscheinlich der Fall, dass diese Sperre auf dem alten Server stattfand, aber niemand zusah? Vergleichen Sie Ihre my.cnf-Zeile für Zeile zwischen Hosts und stellen Sie insbesondere sicher, dass Ihr key_buffer richtig eingestellt ist.
randomx
Wir hatten mehrere andere Leistungsprobleme auf dem alten Server und haben uns oft die Prozessliste angesehen. Es gab hauptsächlich viele Schlafvorgänge, aber wir haben keine Wartevorgänge bemerkt (ich habe diese Informationen im Allgemeinen das erste Mal auf diesem neuen Server gesehen). Mein Kollege hat die alte my.cnf kopiert und die Werte an die neue vorhandene Hardware angepasst, aber es gab nicht viele Einträge. Ich habe auch die Ausgaben von "SHOW VARIABLES" verglichen, wusste aber nicht wirklich, wonach ich suchen sollte. Wir werden den Schlüsselpuffer morgen erneut überprüfen, danke für Ihren Kommentar.
32bitfloat
Wir hatten kürzlich ein ähnliches Problem. Anfangs war unser key_buffer_sizeeingestellt auf 1GB. Erhöhen Sie dies, um 10GBdas Problem zu reduzieren.
Haluk
@ Rick James, danke. Du hast mir heute viel Ärger erspart. Haben Sie eine Wunschliste bei Amazon oder woanders? :) Ich habe query_cache_limit auf 1024 eingerichtet. Es gibt jetzt kein Sperrproblem. Ich habe es zuerst in Variablen vom MySQL-Client aus gemacht. set global query_cache_limit = 1024; Jetzt werde ich es an my.cnf schreiben. Diese Lösung gab mir die Zeit, die Migration von Innodb ohne Stress zu planen. Vielen Dank.

Antworten:

8

Die MyISAM Storage Engine ist bekannt dafür, dass sie vollständige Tabellensperren für DML (INSERTs, UPDATEs, DELETEs) durchführt. InnoDB würde dieses Problem definitiv langfristig lösen.

Ich schrieb über Vor- und Nachteile der Verwendung von MyISAM vs InnoDB

In Bezug auf Ihre aktuelle Frage ist hier ein mögliches Szenario:

  • articleund article_commentssind beide MyISAM-Tabellen
  • article_commentshat einen oder mehrere Indizes mit statusals Spalte
  • Indexseitenaktualisierungen für article_commentswerden im MyISAM-Schlüsselpuffer (Größe nach key_buffer_size ) zwischengespeichert, wodurch alte Indexseiten aus dem MyISAM-Schlüsselpuffer entfernt werden
  • Sie haben SELECT-Abfragen, die JOINs zwischen articleund ausführenarticle_comments

In meinem vorgeschlagenen Szenario können SELECTs für die articleTabelle daran gehindert werden, Schreibvorgänge zuzulassen, da darauf gewartet werden muss article_comments, dass sie frei von DML sind (in diesem Fall ein UPDATE).

RolandoMySQLDBA
quelle
Vielen Dank für Ihre Antwort (und die Links), Ihr Szenario ist real. Mir war nicht klar, dass die meisten ausgewählten Artikel tatsächlich in die Kommentartabelle aufgenommen wurden (oder mit anderen Worten, die unvollständigen Aussagen in der Prozessliste von phpmyadmin). Kennen Sie eine kurzfristige Lösung, um das mehrfache Warten von Anfragen zu verhindern? Ich habe es bereits mit "UPDATE LOW_PRIORITY" in der spezifischen Anweisung versucht, aber das hat keine nennenswerten Änderungen vorgenommen. Wir werden in Zukunft wirklich zu innodb wechseln, aber ich frage mich, ob es derzeit einen Weg gibt, eine Verbesserung zu erzielen.
32bitfloat
Ultimative Lösung: Konvertieren Sie Tabellen in InnoDB. Siehe meinen Beitrag dba.stackexchange.com/a/9422/877 darüber, wie man alles MyISAM in InnoDB konvertiert
RolandoMySQLDBA
7

Zu diesem Zeitpunkt wird die gesamte Seite langsam. Die Datenbank selbst ist minutenlang beschäftigt.

Riecht, als hättest du einen großen Query_cache?

mysql> SHOW VARIABLES LIKE 'query_cache%';
+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| query_cache_limit            | 1048576  |
| query_cache_min_res_unit     | 4096     |
| query_cache_size             | 16777216 | -- Not over 50M
| query_cache_type             | DEMAND   | -- Only if using SQL_CACHE
| query_cache_wlock_invalidate | OFF      |
+------------------------------+----------+

Bei Produktionssystemen mit vielen Schreibvorgängen können Sie den query_cache auch deaktivieren.

Alle Einträge in der query_cache für die angegebene Tabelle gelöscht werden , wenn jede Schreib auf diese Tabelle auftritt. Je größer die Qualitätskontrolle, desto langsamer ist diese Aufgabe.

MyISAM verwendet Sperren auf Tabellenebene. Lese- und Schreibvorgänge können nicht gleichzeitig (in derselben Tabelle) erfolgen. Roh, aber effektiv.

Rick James
quelle
1
Nun ja. Wir haben ungefähr 64 Millionen Caches. Vielen Dank für diese Informationen, die für mich neu waren. Wir hatten jedoch den gleichen Wert auf dem alten Server, auf dem wir die Tablelockings nicht bemerkt haben. Wir haben bereits begonnen, zu InnoDB zu wechseln, aber diese Tatsache bleibt ein Rätsel ...
32bitfloat