Ich entwickle ein Programm in Python, das mit MySQLdb auf eine MySQL-Datenbank zugreift. In bestimmten Situationen muss ich einen INSERT- oder REPLACE-Befehl in vielen Zeilen ausführen. Ich mache es gerade so:Warum ist Executemany in Python MySQLdb langsam?
db.execute("REPLACE INTO " + table + " (" + ",".join(cols) + ") VALUES" +
",".join(["(" + ",".join(["%s"] * len(cols)) + ")"] * len(data)),
[row[col] for row in data for col in cols])
Es funktioniert gut, aber es ist irgendwie peinlich. Ich habe mich gefragt, ob ich es einfacher machen könnte, zu lesen, und ich habe von dem Befehl executemany erfahren. Ich änderte meinen Code, um wie folgt auszusehen:
db.executemany("REPLACE INTO " + table + " (" + ",".join(cols) + ") " +
"VALUES(" + ",".join(["%s"] * len(cols)) + ")",
[tuple(row[col] for col in cols) for row in data])
Es funktionierte immer noch, aber es lief viel langsamer. In meinen Tests lief es für relativ kleine Datensätze (etwa 100-200 Zeilen) etwa 6-mal langsamer. Für große Datenmengen (etwa 13.000 Zeilen, die größte, die ich erwarten würde), lief es etwa 50 mal langsamer. Warum macht es das?
Ich möchte meinen Code wirklich vereinfachen, aber ich möchte nicht den großen Rückgang in der Leistung. Kennt jemand irgendeinen Weg, um es schneller zu machen?
Ich benutze Python 2.7 und MySQLdb 1.2.3. Ich habe versucht, an der setupputsize-Funktion herumzubasteln, aber das schien nichts zu tun. Ich habe den MySQLdb-Quellcode angeschaut und es sieht so aus, als ob er nichts tun sollte.
Wie viele Zeilen werden eingefügt/ersetzt? Ihre zweite Anweisung erstellt eine riesige Liste im Speicher, bevor sie an mysql übergeben wird. – nosklo
Ich ersetze bis zu 13.000 Zeilen. Ich denke nicht, dass das Erstellen der Liste der Flaschenhals ist. Wenn ich die Liste erstelle, sie aber nicht an den db-Cursor übergebe, braucht es kaum Zeit. –
(Ich werde die Frage nicht beantworten, aber ...) 'INSERT ... ON DUPLICATE KEY UPDATE ...' ist fast immer besser als 'REPLACE ...'. –