Leistung eines Triggers gegenüber einer gespeicherten Prozedur in MySQL

10

Ein Beitrag hier auf DBA.StackExchange ( Was sind die Best Practices für Trigger, um eine Revisionsnummer für Datensätze beizubehalten? ) Hat eine interessante (zumindest für mich interessante) Frage zur Leistung in MySQL aufgeworfen.

Der Kontext ist, dass wir für jede aktualisierte Zeile einen Datensatz in eine Tabelle einfügen möchten. Bevor die Zeile aktualisiert wird, möchten wir einen vorherigen Wert speichern und dann eine der Spalten (eine "Versions" -Spalte) erhöhen.

Wenn wir dies in einem Trigger tun, funktioniert es gut. Für MySQL sind die Trigger Zeile für Zeile , daher wäre dies eine einfache Lösung. Wählen Sie die aktuell in der Tabelle enthaltenen Daten aus, fügen Sie sie in die Protokollierungstabelle ein und aktualisieren Sie die Spalte "Version" in den neuen Daten.

Es ist jedoch möglich, diese Logik in eine gespeicherte Prozedur zu verschieben. Wenn Sie dies tun, führen Sie die Einfügung durch und erhöhen dann die Spalte "Version" in der Tabelle. Das Ganze würde auf Set basieren.

Wenn es also darum geht, diese Einfügung durchzuführen, wäre dies leistungsfähiger, wenn der satzbasierte Ansatz für gespeicherte Prozeduren oder ein triggerbasierter Ansatz verwendet wird?

Diese Frage bezieht sich auf MySQL (da es zeilenweise Trigger hat), obwohl sie auch für andere zeilenweise Trigger-DBMS gelten kann.

Richard
quelle
1
Eine Sache, die Sie beachten sollten, wenn Sie die Versionslogik auf eine gespeicherte Prozedur übertragen möchten - wie hoch sind Sie, wenn jemand unter Umgehung Ihres Prüfmechanismus irgendwie direkt in die Tabelle schreibt?
Billinkc
Genau. Aber am anderen Ende der Skala möchten Sie diese Protokollierung möglicherweise unter bestimmten Umständen absichtlich umgehen. Das ist natürlich eine ganz andere Frage . Ich bin wirklich nur neugierig auf die Auswirkungen auf die Leistung.
Richard

Antworten:

6

Der Einfachheit halber sind Trigger der richtige Weg, um jede Art von Nachverfolgung von Datenbankänderungen zu implementieren. Sie müssen jedoch wissen, was unter der Haube passiert, wenn Sie Trigger verwenden.

Laut MySQL Stored Procedure Programming wird auf Seite 256 unter der Überschrift "Trigger Overhead" Folgendes angegeben:

Es ist wichtig zu bedenken, dass Trigger der DML-Anweisung, für die sie gelten, notwendigerweise zusätzlichen Aufwand hinzufügen. Der tatsächliche Overhead hängt von der Art des Triggers ab. Da jedoch alle MySQL-Trigger FÜR JEDE REIHE ausgeführt werden, kann sich der Overhead für Anweisungen, die eine große Anzahl von Zeilen verarbeiten, schnell ansammeln. Sie sollten daher vermeiden, teure SQL-Anweisungen oder Prozedurcode in Trigger zu setzen.

Eine erweiterte Erläuterung des Trigger-Overheads finden Sie auf den Seiten 529-531. Der abschließende Punkt aus diesem Abschnitt lautet wie folgt:

Die Lektion hier lautet: Da der Triggercode für jede von einer DML-Anweisung betroffene Zeile einmal ausgeführt wird, kann der Trigger leicht zum wichtigsten Faktor für die DML-Leistung werden. Code im Trigger-Body muss so leicht wie möglich sein, und insbesondere sollten alle SQL-Anweisungen im Trigger nach Möglichkeit von Indizes unterstützt werden.

Nicht im Buch erwähnt ist ein weiterer Faktor bei der Verwendung von Triggern: Wenn es um die Überwachungsprotokollierung geht, beachten Sie bitte, bei was Sie Daten anmelden. Ich sage dies, weil jedes INSERT in einer MyISAM-Tabelle eine vollständige Tabellensperre während des INSERT erzeugt, falls Sie sich für die Anmeldung bei einer MyISAM-Tabelle entscheiden. Dies kann zu einem schwerwiegenden Engpass in einer Umgebung mit hohem Datenverkehr und hohen Transaktionen werden. Wenn der Trigger gegen eine InnoDB-Tabelle gerichtet ist und Sie Änderungen in MyISAM innerhalb des Triggers protokollieren, wird die ACID-Konformität heimlich deaktiviert (dh Blocktransaktionen auf Autocommit-Verhalten reduziert), was nicht rückgängig gemacht werden kann.

Bei Verwendung von Triggern für InnoDB-Tabellen und Protokollierung von Änderungen

  • Die Tabelle, in der Sie sich anmelden, ist ebenfalls InnoDB
  • Sie haben die automatische Festschreibung deaktiviert
  • Sie richten START TRANSACTION ... COMMIT / ROLLBACK-Blöcke gründlich ein

Auf diese Weise können Überwachungsprotokolle wie Haupttabellen von COMMIT / ROLLBACK profitieren.

In Bezug auf die Verwendung gespeicherter Prozeduren müssten Sie die gespeicherte Prozedur an jedem Punkt der DML sorgfältig gegen die zu verfolgende Tabelle aufrufen. Man könnte leicht die Protokollierung von Änderungen angesichts von Zehntausenden von Zeilen Anwendungscode übersehen. Wenn Sie einen solchen Code in einen Trigger einfügen, werden alle diese DML-Anweisungen nicht mehr gefunden.

VORBEHALT

Je nachdem, wie komplex der Auslöser ist, kann es sich dennoch um einen Engpass handeln. Wenn Sie Engpässe bei der Überwachungsprotokollierung reduzieren möchten, können Sie Folgendes tun. Es wird jedoch eine kleine Änderung der Infrastruktur erforderlich sein.

Erstellen Sie mit Standardhardware zwei weitere DB-Server

Dadurch wird der Server reduziert, um die Schreib-E / A in der Hauptdatenbank (MD) aufgrund der Überwachungsprotokollierung zu reduzieren. So können Sie es erreichen:

Schritt 01) Aktivieren Sie die binäre Protokollierung in der Hauptdatenbank.

Schritt 02) Richten Sie MySQL (dieselbe Version wie MD) mit einem kostengünstigen Server mit aktivierter binärer Protokollierung ein. Dies wird DM sein. Richten Sie die Replikation von MD auf DM ein.

Schritt 03) Richten Sie MySQL (dieselbe Version wie MD) mit einem zweiten kostengünstigen Server mit deaktivierter binärer Protokollierung ein. Richten Sie jede Prüftabelle für die Verwendung von --replicate-do-table ein . Dies wird AU sein. Richten Sie die Replikation von DM nach AU ein.

Schritt 04) mysqldump die Tabellenstrukturen von MD und laden Sie es in DM und AU.

Schritt 05) Konvertieren Sie alle Audit-Tabellen in MD, um die BLACKHOLE-Speicher-Engine zu verwenden

Schritt 06) Konvertieren Sie alle Tabellen in DM und AU, um die BLACKHOLE-Speicher-Engine zu verwenden

Schritt 07) Konvertieren Sie alle Audit-Tabellen in AU, um die MyISAM-Speicher-Engine zu verwenden

Wenn Sie fertig sind

  • DM repliziert von MD und zeichnet Inhalte nur in seinem Binärprotokoll auf
  • Mit dem Filter --replicate-do-table für alle Audit-Tabellen wird AU von DM repliziert

Dadurch werden Überwachungsinformationen auf einem separaten DB-Server gespeichert und die normalerweise auftretende Verschlechterung der Schreib-E / A verringert.

RolandoMySQLDBA
quelle
Enorme Antwort +++ 1
b_dubb
1

Hier ist ein Ansatz, um dieses Update in großen Mengen durchzuführen.

Für dieses Beispiel

  • table_A hat die PRIMARY KEY-ID
  • Sie erstellen eine Tabelle mit dem Namen table_A_Keys2Update mit nur der ID als PRIMARY KEY
  • Sie füllen table_A_Keys2Update mit IDs von table_A, von denen Sie wissen, dass sie aktualisiert werden müssen

Gehen Sie wie folgt vor, um table_A_Keys2Update zu erstellen:

CREATE TABLE table_A_Keys2Update SELECT id FROM table_A;
ALTER TABLE table_A_Keys2Update ADD PRIMARY KEY (id);

Nachdem Sie table_A_Keys2Update mit den IDs gefüllt haben, deren Revisionsnummer erhöht werden muss, führen Sie das folgende UPDATE JOIN aus, um die Revisionsnummer aller Zeilen zu erhöhen, deren ID sowohl in table_A als auch in table_A_Keys2Update enthalten ist:

UPDATE table_A A INNER JOIN table_A_Keys2Update B USING (id)
SET A.revision = A.revision + 1;

Diese einzeilige Abfrage kann einen Trigger und eine gespeicherte Prozedur ersetzen.

Optional können Sie diese eine Abfrage in eine gespeicherte Prozedur einfügen und auf Wunsch aufrufen.

RolandoMySQLDBA
quelle
Es ist wirklich die Beilage, auf die ich neugierig bin. Wenn Sie INSERT INTO audit SELECT <was auch immer> FROM <primäre_Tabelle> WHERE <Parameter aus gespeicherter Prozedur> verwenden, können Sie das Einfügen in großen Mengen durchführen. Im Trigger würden Sie einfach INSERT INTO audit VALUES <Daten aus der aktualisierten Zeile> einfügen . Wäre die einzeilige zeilenweise Einfügung also schneller als die Masseneinfügung?
Richard
Der Einfachheit halber wäre der Auslöser viel besser. 1) Vorausgesetzt, in der Primary_Table werden in der Mitte von Spitzenzeiten keine Bulks-Inserts eingefügt. 2) Audit-Informationen müssen zu jedem Zeitpunkt bei Bedarf gelesen werden. 3) Ihre Site ist wenig gehandelt.
RolandoMySQLDBA