it-swarm.com.de

Warum dauert eine Insert-Abfrage gelegentlich so lange?

Dies ist ein ziemlich einfaches Problem. Das Einfügen von Daten in die Tabelle funktioniert normalerweise einwandfrei, es sei denn, einige Male dauert die Einfügeabfrage einige Sekunden. (Ich bin not versuche, Daten in großen Mengen einzufügen.) Ich setze eine Simulation für den Einfügeprozess ein, um herauszufinden, warum die Einfüge-Abfrage gelegentlich mehr als 2 Sekunden dauert. Joshua schlug vor, dass die Indexdatei angepasst werden könnte; Ich habe die ID (Primärschlüsselfeld) entfernt, aber die Verzögerung tritt immer noch auf.

Ich habe eine MyISAM-Tabelle: daniel_test_insert (diese Tabelle startet vollständig leer):

create table if not exists daniel_test_insert ( 
    id int unsigned auto_increment not null, 
    value_str varchar(255) not null default '', 
    value_int int unsigned default 0 not null, 
    primary key (id) 
)

Ich füge Daten ein und manchmal dauert eine Insert-Abfrage> 2 Sekunden. Es gibt keine Lesevorgänge für diese Tabelle - Schreibt nur seriell durch ein einzelnes Thread-Programm.

Ich habe dieselbe Abfrage 100.000 Mal ausgeführt, um herauszufinden, warum die Abfrage gelegentlich lange dauert. Bisher scheint es ein zufälliges Vorkommen zu sein.

Diese Abfrage hat beispielsweise 4.194 Sekunden gedauert (sehr lange Zeit für eine Einfügung):

Query: INSERT INTO daniel_test_insert SET value_int=12345, value_str='afjdaldjsf aljsdfl ajsdfljadfjalsdj fajd as f' - ran for 4.194 seconds
status               | duration | cpu_user  | cpu_system | context_voluntary | context_involuntary | page_faults_minor
starting             | 0.000042 | 0.000000  | 0.000000   | 0                 | 0                   | 0                
checking permissions | 0.000024 | 0.000000  | 0.000000   | 0                 | 0                   | 0                
Opening tables       | 0.000024 | 0.001000  | 0.000000   | 0                 | 0                   | 0                
System lock          | 0.000022 | 0.000000  | 0.000000   | 0                 | 0                   | 0                
Table lock           | 0.000020 | 0.000000  | 0.000000   | 0                 | 0                   | 0                
init                 | 0.000029 | 0.000000  | 0.000000   | 1                 | 0                   | 0                
update               | 4.067331 | 12.151152 | 5.298194   | 204894            | 18806               | 477995           
end                  | 0.000094 | 0.000000  | 0.000000   | 8                 | 0                   | 0                
query end            | 0.000033 | 0.000000  | 0.000000   | 1                 | 0                   | 0                
freeing items        | 0.000030 | 0.000000  | 0.000000   | 1                 | 0                   | 0                
closing tables       | 0.125736 | 0.278958  | 0.072989   | 4294              | 604                 | 2301             
logging slow query   | 0.000099 | 0.000000  | 0.000000   | 1                 | 0                   | 0                
logging slow query   | 0.000102 | 0.000000  | 0.000000   | 7                 | 0                   | 0                
cleaning up          | 0.000035 | 0.000000  | 0.000000   | 7                 | 0                   | 0

(Dies ist eine abgekürzte Version des Befehls SHOW PROFILE. Ich habe die Spalten ausgegeben, die alle Null waren.)

Jetzt enthält das Update eine unglaubliche Anzahl von Kontextwechseln und kleinere Seitenfehler. Opened_Tables erhöht sich um 1 pro 10 Sekunden in dieser Datenbank (es läuft kein Speicherplatz für table_cache)

Statistiken:

  • MySQL 5.0.89

  • Hardware: 32 GB RAM/8 Kerne bei 2,66 GHz; RAID 10 SCSI-Festplatten (SCSI II ???)

  • Ich habe die Festplatten und den RAID-Controller abgefragt: Es werden keine Fehler gemeldet . Die CPUs sind zu etwa 50% im Leerlauf.

  • iostat -x 5 (meldet weniger als 10% Auslastung für Festplatten) Oberste Auslastungsrate für durchschnittlich 1 für 1 Minute (normal für unsere Datenbankmaschine)

  • Swap Space hat 156k verwendet (32 GB RAM)

Ich kann nicht herausfinden, was diese Performance-Verzögerung verursacht. Dies passiert NICHT bei unseren Low-Load-Slaves, sondern nur bei unserem High-Load-Master. Dies gilt auch für Speicher- und Innodb-Tabellen. Hat jemand irgendwelche Vorschläge? (Dies ist ein Produktionssystem, also nichts Exotisches!) 

33
Daniel

Ich habe das gleiche Phänomen auf meinen Systemen festgestellt. Abfragen, die normalerweise eine Millisekunde dauern, dauern plötzlich 1-2 Sekunden. In allen meinen Fällen handelt es sich um einfache INSERT/UPDATE/REPLACE-Anweisungen für eine einzige Tabelle - nicht für SELECTs. Es ist keine Belastung, Blockierung oder Gewindeaufbau erkennbar. 

Ich hatte vermutet, dass dies durch das Löschen schmutziger Seiten, das Löschen von Änderungen auf der Festplatte oder einen versteckten Mutex verursacht wurde, aber ich muss ihn noch einschränken.

Auch ausgeschlossen

  • Serverlast - keine Korrelation mit hoher Last
  • Engine - passiert mit InnoDB/MyISAM/Memory
  • MySQL Query Cache - geschieht unabhängig davon, ob er aktiviert oder deaktiviert ist
  • Protokollrotationen - keine Korrelation bei Ereignissen

Die einzige andere Beobachtung, die ich an diesem Punkt habe, ergibt sich aus der Tatsache, dass ich dieselbe Datenbank auf mehreren Computern ausführte. Ich habe eine umfangreiche Lese-Anwendung, daher verwende ich eine Umgebung mit Replikation - der größte Teil der Last liegt auf den Slaves. Ich habe bemerkt, dass das Phänomen dort mehr auftritt, obwohl der Master nur minimal belastet wird. Obwohl ich keine Sperrprobleme sehe, kann es sein, dass Innodb/Mysql Probleme mit (Thread) Parallelität hat? Denken Sie daran, dass die Aktualisierungen auf dem Slave Single-Threading sind.

MySQL-Version 5.1.48

Update

Ich glaube, ich habe eine Führung für das Problem in meinem Fall. Auf einigen meiner Server habe ich dieses Phänomen an mehr als den anderen bemerkt. Als ich sah, was zwischen den verschiedenen Servern anders war, und die Dinge um sich herum zu verändern, wurde ich zur MySQL-Systemvariable innodbinnodb_flush_log_at_trx_commit geführt.

Ich fand das doc etwas umständlich zu lesen, aber innodb_flush_log_at_trx_commit kann die Werte von 1,2,0 annehmen:

  • Bei 1 wird der Protokollpuffer für jedes Commit in die Protokolldatei ___ geschrieben. Die Logdatei Wird für jedes Commit auf die Festplatte geleert.
  • Bei 2 wird der Protokollpuffer für jede Festschreibung in die Protokolldatei ___ geschrieben. Die Protokolldatei ___ wird ungefähr alle 1-2 Sekunden auf die Festplatte geleert.
  • Für 0 wird der Protokollpuffer jede Sekunde in die Protokolldatei Und die Protokolldatei Wird jede Sekunde auf die Festplatte geschrieben.

In der Reihenfolge (1,2,0), wie berichtet und dokumentiert, sollten Sie mit zunehmender Leistung im Handel für ein erhöhtes Risiko geraten.

Trotzdem stellte ich fest, dass die Server mit innodb_flush_log_at_trx_commit=0 schlechter abschnitten (d. H. 10-100 mal mehr "lange Updates" hatten) als die Server mit innodb_flush_log_at_trx_commit=2. Darüber hinaus verbesserte sich die Situation sofort auf die schlechten Instanzen, als ich sie auf 2 umstellte (beachten Sie, dass Sie sie sofort ändern können).

Meine Frage ist also: Was ist für Sie bestimmt? Beachten Sie, dass ich diesen Parameter nicht beschuldige, sondern hervorheben möchte, dass der Kontext mit diesem Problem zusammenhängt.

20
Riedsio

Der erste Tipp, den ich Ihnen geben würde, ist, die Autocommit-Funktion zu deaktivieren und dann manuell zu bestätigen.

LOCK TABLES a WRITE;
... DO INSERTS HERE
UNLOCK TABLES;

Dies wirkt sich positiv auf die Leistung aus, da der Indexpuffer nur einmal auf die Festplatte geschrieben wird, nachdem alle INSERT-Anweisungen abgeschlossen wurden. Normalerweise würde es so viele Indexpufferlöschungen geben wie INSERT-Anweisungen. 

Aber das Beste, was Sie tun können, und wenn dies in Ihrer Anwendung möglich ist, führen Sie eine Masseneinfügung mit einer einzigen Auswahl aus.

Dies erfolgt über Vector Binding und ist der schnellste Weg, den Sie gehen können.

Instead
of:
"INSERT INTO tableName values()"
DO
"INSERT INTO tableName values(),(),(),().......(n) " ,

Beachten Sie diese Option jedoch nur, wenn die Parametervektorbindung mit dem von Ihnen verwendeten MySQL-Treiber möglich ist.

Ansonsten würde ich zur ersten Möglichkeit neigen und den Tisch für jeweils 1000 Einsätze verriegeln. Sperren Sie es nicht für 100-KByte-Inserts, da Sie einen Pufferüberlauf erhalten.

1
BitKFu

Ich hatte dieses Problem mit INNODB-Tabellen. (und INNODB-Indizes sind noch langsamer als MYISAM zu beschreiben)

Ich nehme an, Sie führen mehrere andere Abfragen in einigen anderen Tabellen durch. Das Problem wäre also, dass MySQL Festplattenschreibvorgänge in Dateien behandeln muss, die größer werden und zusätzlichen Speicherplatz für diese Dateien zuweisen müssen. 

Wenn Sie MYISAM-Tabellen verwenden, empfehle ich dringend die Verwendung von 

LOAD DATA INFILE 'file-on-disk' INTO TABLE `tablename` 

befehl; MYISAM ist damit sensationell schnell (auch mit Primärschlüsseln), und die Datei kann als csv formatiert werden, und Sie können die Spaltennamen angeben (oder Sie können NULL als Wert für das Autoincrement-Feld angeben).

MYSQL-Dokument hier anzeigen .

1
Jay

Können Sie eine weitere Tabelle mit 400 (nicht Null) Spalten erstellen und den Test erneut ausführen? Wenn die Anzahl der langsamen Einfügungen erhöht wurde, könnte dies bedeuten, dass MySQL Zeit beim Schreiben Ihrer Datensätze verschwendet. (Ich weiß nicht, wie es funktioniert, aber er kann mehr Blöcke zuordnen oder etwas bewegen, um eine Fragmentierung zu vermeiden ... weiß wirklich nicht)

1

Wir haben genau das gleiche Problem gefunden und hier berichtet: http://bugs.mysql.com/bug.php?id=62381

Wir verwenden 5.1.52 und haben noch keine Lösung. Möglicherweise müssen Sie QC ausschalten, um diesen Perfomance-Treffer zu vermeiden.

1
fxwan

Wir haben ein Upgrade auf MySQL 5.1 durchgeführt, und während dieses Ereignisses wurde der Query-Cache zu einem Problem mit einer Menge von "Freeing items?" Thread-Zustände. Dann haben wir den Abfrage-Cache entfernt.

Dieses Problem wurde durch das Upgrade auf MySQL 5.1 oder das Entfernen des Abfrage-Caches behoben.

Zu Ihrer Information für zukünftige Leser.

-Daniel

0
Daniel

Um zu prüfen, ob sich Ihre Festplatte schlecht verhält und Sie sich unter Windows befinden, können Sie eine Batch-Cmd-Datei erstellen, die 10.000 Dateien erstellt:

@echo OFF
FOR /L %%G IN (1, 1, 10000) DO TIME /T > out%%G.txt

speichern Sie es in einem temporären Verzeichnis wie test.cmd

Aktivieren Sie Befehlserweiterungen, auf denen CMD ausgeführt wird, mit dem Parameter/E: ON

CMD.exe /E:ON

Führen Sie dann Ihren Stapel aus und prüfen Sie, ob die Zeit zwischen der ersten und der letzten ausgehenden Datei in Sekunden oder Minuten variiert. 

Unter Unix/Linux können Sie ein ähnliches Shell-Skript schreiben. 

0
vulkanino

Können Sie die Statistiken des Datenträgersystems überprüfen? Ist die E/A zufrieden? Das klingt nach interner DB-Arbeit, die auf Festplatte/Protokoll läuft. 

0
bigtang

Ist möglicherweise ein SSD-Laufwerk im Server? Einige SSD-Laufwerke leiden unter 'Studder', was Ihr Symptom verursachen kann.

In jedem Fall würde ich versuchen herauszufinden, ob die Verzögerung in MySQL oder im Disk-Subsystem auftritt.

Welches Betriebssystem ist Ihr Server und in welchem ​​Dateisystem befinden sich die MySQL-Daten?

0
Guy Gordon

wenn Sie mehrere Einfügeoperationen mit for-Schleife verwenden, machen Sie nach jeder Schleife eine Pause mit der PHP-Sleep-Funktion ("Zeit in Sekunden").

0
Manish

Lesen Sie dies auf Myisam Performance: http://adminlinux.blogspot.com/2010/05/mysql-allocating-memory-for-caches.html

Suchen nach:

'Die MyISAM-Schlüsselblockgröße Die Schlüsselblockgröße ist wichtig' (mit Ausnahme der einfachen Anführungszeichen), dies könnte der Fall sein. Ich denke, sie haben einige dieser Probleme mit 5.1 behoben

0
Phill Pafford