Wie verwende ich die Einfügungsverzögerung mit der InnoDB-Engine und verwende weniger Verbindung für Einfügeanweisungen?

10

Ich arbeite an einer Anwendung, die viele Datenbankschreibvorgänge, ungefähr 70% Einfügungen und 30% Lesevorgänge umfasst. Dieses Verhältnis würde auch Aktualisierungen einschließen, die ich als ein Lese- und ein Schreibvorgang betrachte. Durch Einfügeanweisungen fügen mehrere Clients Daten über die folgende Einfügeanweisung in die Datenbank ein:

$mysqli->prepare("INSERT INTO `track` (user, uniq_name, ad_name, ad_delay_time ) values (?, ?, ?, ?)");

Die Frage ist, ob ich entweder insert_delay oder mysqli_multi_query verwenden soll , da die insert-Anweisung auf dem Server ~ 100% CPU verwendet. Ich verwende die InnoDB-Engine in meiner Datenbank, sodass ein verzögertes Einfügen nicht möglich ist. Das Einfügen auf dem Server ist ~ 36k / h und 99,89% gelesen. Außerdem verwende ich die select-Anweisung, um dort sieben Mal Daten in einer einzelnen Abfrage abzurufen . Die Ausführung dieser Abfrage auf dem Server dauert 150 Sekunden. Welche Technik oder welchen Mechanismus kann ich für diese Aufgabe verwenden? Mein Serverspeicher ist 2 GB, sollte ich Speicher erweitern?. Schauen Sie sich dieses Problem an, jeder Vorschlag wird mir dankbar sein.

Tabellenstruktur:

+-----------------+--------------+------+-----+-------------------+----------------+
| Field           | Type         | Null | Key | Default           | Extra          |
+-----------------+--------------+------+-----+-------------------+----------------+
| id              | int(11)      | NO   | PRI | NULL              | auto_increment |
| user            | varchar(100) | NO   |     | NULL              |                |
| uniq_name       | varchar(200) | NO   |     | NULL              |                |
| ad_name         | varchar(200) | NO   |     | NULL              |                |
| ad_delay_time   | int(11)      | NO   |     | NULL              |                |
| track_time      | timestamp    | NO   | MUL | CURRENT_TIMESTAMP |                |
+-----------------+--------------+------+-----+-------------------+----------------+

Mein Datenbank-Status zeigt 41.000 Einfügungen (Schreibvorgänge) an, was für meine Datenbank sehr langsam ist.

Datenbankstatus

Shashank
quelle
Können Sie die Definition der Tabelle angeben? (alle Spalten, Datentypen und Indizes)
ypercubeᵀᴹ
Können Sie einen kurzen Ausschnitt von Ihnen geben, SHOW FULL PROCESSLISTwenn es 100% CPU nimmt? Wie viele Verbindungen erlauben Sie und wie viele werden in dieser Zeit genommen?
Derek Downey
Führen Sie diese beiden Abfragen aus: SHOW GLOBAL VARIABLES LIKE 'innodb%';und SELECT VERSION();und zeigen Sie ihre Ausgabe an.
RolandoMySQLDBA
Bitte geben Sie die Anzahl der Einfügungen pro Sekunde an, die Sie ausführen.
dabest1
Ihr Code ist sehr anfällig für SQL-Injection. Verwenden Sie vorbereitete Anweisungen und parametrisierte Werte.
Aaron Brown

Antworten:

11

Da Sie mehr Schreibvorgänge als Lesevorgänge haben, möchte ich Folgendes empfehlen

Eine anständige Abstimmung von InnoDB wäre der Schlüssel

Pufferpool ( Größe von innodb_buffer_pool_size )

Da InnoDB INSERT DELAYED nicht unterstützt , ist die Verwendung eines großen InnoDB- Pufferpools am nächsten an INSERT DELAYED. Alle DML (INSERTs, UPDATEs und DELETEs) werden im InnoDB-Pufferpool zwischengespeichert. Transaktionsinformationen für die Schreibvorgänge werden sofort in die Redo-Protokolle (ib_logfile0, ib_logfile1) geschrieben. Die im Pufferpool veröffentlichten Schreibvorgänge werden regelmäßig über ibdata1 (InsertBuffer für Sekundärindizes, Double Write Buffer) vom Speicher auf die Festplatte geleert. Je größer der Pufferpool ist, desto mehr INSERTs können zwischengespeichert werden. Verwenden Sie in einem System mit 8 GB oder mehr RAM 75-80% des RAM als innodb_buffer_pool_size. In einem System mit sehr wenig RAM 25% (um das Betriebssystem aufzunehmen).

CAVEAT: Sie können innodb_doublewrite auf 0 setzen, um das Schreiben noch weiter zu beschleunigen, jedoch mit dem Risiko der Datenintegrität. Sie können die Arbeit auch beschleunigen, indem Sie innodb_flush_method auf O_DIRECT setzen, um zu verhindern, dass InnoDB an das Betriebssystem zwischengespeichert wird.

Protokolle wiederholen ( Größe von innodb_log_file_size )

Standardmäßig heißen die Redo-Protokolle ib_logfile0 und ib_logfile1 und betragen jeweils 5 MB. Die Größe sollte 25% der Größe innodb_buffer_pool_size betragen. Wenn die Redo-Protokolle bereits vorhanden sind, fügen Sie die neue Einstellung in my.cnf hinzu, fahren Sie mysql herunter, löschen Sie sie und starten Sie mysql neu .

Protokollpuffer ( Größe von innodb_log_buffer_size )

Der Protokollpuffer enthält Änderungen im RAM, bevor sie in die Redo-Protokolle übertragen werden. Der Standardwert ist 8M. Je größer der Protokollpuffer ist, desto weniger Festplatten-E / A. Seien Sie vorsichtig bei sehr großen Transaktionen, da dies COMMITs um Millisekunden verlangsamen kann.

Zugriff auf mehrere CPUs

MySQL 5.5 und das MySQL 5.1 InnoDB-Plugin verfügen über Einstellungen, mit denen InnoDB Storage Engine auf mehrere CPUs zugreifen kann. Hier sind die Optionen, die Sie einstellen müssen:

  • innodb_thread_concurrency legt die Obergrenze für die Anzahl gleichzeitiger Threads fest, die InnoDB offen halten kann. Es wird normalerweise empfohlen, hierfür die Einstellung (2 x Anzahl der CPUs) + Anzahl der Festplatten festzulegen. Letztes Jahr habe ich auf der Percona NYC-Konferenz aus erster Hand erfahren, dass Sie diesen Wert auf 0 setzen sollten, um die InnoDB Storage Engine zu warnen, die beste Anzahl von Threads für die Umgebung zu finden, in der sie ausgeführt wird.
  • innodb_concurrency_tickets legt die Anzahl der Threads fest, die die Parallelitätsprüfung ungestraft umgehen können. Nach Erreichen dieses Grenzwerts wird die Überprüfung der Thread-Parallelität wieder zur Norm.
  • innodb_commit_concurrency legt die Anzahl der gleichzeitigen Transaktionen fest, die festgeschrieben werden können. Da der Standardwert 0 ist, kann durch Nichteinstellung einer beliebigen Anzahl von Transaktionen gleichzeitig festgeschrieben werden.
  • innodb_thread_sleep_delay legt die Anzahl der Millisekunden fest, die ein InnoDB-Thread ruhen kann, bevor er erneut in die InnoDB-Warteschlange eingeht . Die Standardeinstellung ist 10000 (10 Sek.).
  • innodb_read_io_threads (setzen Sie dies auf 3000) und innodb_write_io_threads (setzen Sie dies auf 7000) (beide seit MySQL 5.1.38) weisen die angegebene Anzahl von Threads für Lese- und Schreibvorgänge zu. Der Standardwert ist 4 und das Maximum ist 64. Setzen Sie diese auf 64. Setzen Sie außerdem die innodb_io_capacity auf 10000.

Upgrade auf MySQL 5.5

Wenn Sie über MySQL 5.0 verfügen, aktualisieren Sie auf MySQL 5.5. Wenn Sie MySQL 5.1.37 oder früher haben, aktualisieren Sie auf MySQL 5.5. Wenn Sie MySQL 5.1.38 oder höher haben und in MySQL 5.1 bleiben möchten, installieren Sie das InnoDB-Plugin. Auf diese Weise können Sie alle CPUs für InnoDB nutzen.

RolandoMySQLDBA
quelle
Mein Serverspeicher ist 2 GB, also habe ich laut Speicher den Innodb-Pufferpool auf 500 MB und die Protokolldateien zu 25% auf Pool gesetzt und den Protokollpuffer auf 64 MB. Trotzdem ist der Server stark ausgelastet. Soll ich den Speicher aktualisieren? Auch mein Server ist auf 32-Bit-Ubuntu, so dass ich maximal 4 GB Speicher einstellen kann.
Shashank
Wenn der Server nur für MySQL ist (kein Apache, kein PHP), kann innodb_buffer_pool_size 75% von 2 GB betragen, was 1536 MB entspricht. Wenn Sie auf 4 GB aktualisieren, kann innodb_buffer_pool_size 3G betragen. Protokolldateien sollten wie angegeben 25% des Pufferpools ausmachen.
RolandoMySQLDBA
Auf dem Server werden Apache2, MySQL und PHP ausgeführt. Sollte ich in dieser Situation ein Upgrade des Speichers durchführen oder gibt es eine optimale Lösung außer für den Innodb-Pufferpool?
Shashank
Dieser Typ ist nicht einverstanden mit Ihnen: percona.com/blog/2008/11/21/… Schwer mit Percona zu streiten.
Zenexer
Rolando - schlagen Sie vor, die Antwort mit Updates für 5.6 und 5.7 zu ergänzen. Die Standardeinstellungen haben sich geändert. andere Einstellungen sind verfügbar; usw. Vielleicht enthalten Percona und MariaDB und 8.0 Tipps.
Rick James
2

INT (2) verwendet immer noch 4 Bytes - vielleicht meinten Sie TINYINT UNSIGNED?

Wie viele verschiedene Werte in setno? Wenn es klein ist, wird der SCHLÜSSEL (setno) niemals verwendet. INSERTing muss diesen Index aktualisieren. Durch Entfernen des Schlüssels wird INSERT etwas beschleunigt.

CHAR (10) - Ist flagimmer 10 Zeichen lang? Und in utf8? Vielleicht könnten Sie das Flag VARCHAR (10) CHARACTER SET ascii verwenden

Stapeln Sie Ihre Beilagen - 100 auf einmal laufen zehnmal so schnell. (Über 100 steigt die Rendite.)

Was ist der Wert von Autocommit? Wickeln Sie jedes INSERT in BEGIN ... COMMIT ein? Was ist der Wert von innodb_flush_log_at_trx_commit?

Rick James
quelle
Wie bekomme ich eine Einfügung im Stapel, wenn Daten über eine externe Quelle wie verschiedene Clients mit unterschiedlichen Werten codeeingefügt werden? Ist es zuverlässig, wenn ich Folgendes verwende: Einfügen in t_name (col1, col2, col3) Werte (val1, val2, val3), (val1, val2, val3), (val1, val2, val3), (val1, val2, val3), (val1, val2, val3); code
Shashank
1

Richten Sie eine Warteschlange ein. Die Anwendung schreibt jeweils 1 Zeile in eine Warteschlange und nimmt dann Zeilen heraus und fügt sie stapelweise in eine Datenbank ein, basierend auf der Anzahl der Zeilen, die seit dem letzten Einfügen vergangen sind.

Ich habe gesehen, wo das Stapeln der Einsätze 10.000 auf einmal am schnellsten ist, also müssten Sie testen, um einen Sweet Spot zu finden.

Sie können Ihr eigenes einfaches Warteschlangensystem erstellen oder ein vorhandenes verwenden. Hier einige Beispiele: HornetQ und File :: Queue . Hier ist ein Beitrag auf SE, in dem einige andere gute Optionen aufgelistet sind: Nachrichtenwarteschlangen in Perl, PHP, Python .

dabest1
quelle
Ich stimme diesem Ansatz zu - ich staple alle 5 Sekunden ~ 1500 Einfügungen in einer App und es ist weniger als eine Sekunde. mysql scheint einen intern implementierten Mechanismus zu haben, der Batch-Einfügungen sehr, sehr schnell ermöglicht.
Don Wool