Verwenden von MySQL 5.6 mit der InnoDB-Speicher-Engine für die meisten Tabellen. Die Größe des InnoDB-Pufferpools beträgt 15 GB, und die Innodb DB + -Indizes liegen bei etwa 10 GB. Der Server verfügt über 32 GB RAM und führt Cent OS 7 x64 aus.
Ich habe einen großen Tisch, der über 10 Millionen Datensätze enthält.
Ich erhalte alle 24 Stunden eine aktualisierte Dump-Datei von einem Remote-Server. Die Datei ist im CSV-Format. Ich habe keine Kontrolle über dieses Format. Die Datei ist ~ 750 MB groß. Ich habe versucht, Daten zeilenweise in eine MyISAM-Tabelle einzufügen, und es dauerte 35 Minuten.
Ich muss nur 3 Werte pro Zeile von 10-12 aus der Datei entnehmen und in der Datenbank aktualisieren.
Was ist der beste Weg, um so etwas zu erreichen?
Ich muss das täglich tun.
Momentan sieht Flow so aus:
- mysqli_begin_transaction
- Dump-Datei Zeile für Zeile lesen
- Aktualisieren Sie jeden Datensatz Zeile für Zeile.
- mysqli_commit
Die oben genannten Vorgänge dauern ca. 30-40 Minuten. Dabei werden noch weitere Aktualisierungen durchgeführt, die ich erhalten kann
Wartezeitüberschreitung der Sperre überschritten; Starten Sie die Transaktion erneut
Update 1
Daten laden in neue Tabelle mit LOAD DATA LOCAL INFILE
. In MyISAM hat es gedauert, 38.93 sec
während es in InnoDB 7 Minuten 5,21 Sekunden gedauert hat. Dann habe ich gemacht:
UPDATE table1 t1, table2 t2
SET
t1.field1 = t2.field1,
t1.field2 = t2.field2,
t1.field3 = t2.field3
WHERE t1.field10 = t2.field10
Query OK, 434914 rows affected (22 hours 14 min 47.55 sec)
Update 2
Gleiches Update mit Join-Abfrage
UPDATE table1 a JOIN table2 b
ON a.field1 = b.field1
SET
a.field2 = b.field2,
a.field3 = b.field3,
a.field4 = b.field4
(14 hours 56 min 46.85 sec)
Erläuterungen zu Fragen in Kommentaren:
- Ungefähr 6% der Zeilen in der Tabelle werden von der Datei aktualisiert, aber manchmal können es bis zu 25% sein.
- Es gibt Indizes für die Felder, die aktualisiert werden. Die Tabelle enthält 12 Indizes, und 8 Indizes enthalten die Aktualisierungsfelder.
- Es ist nicht erforderlich , das Update in einer Transaktion durchzuführen. Es kann einige Zeit dauern, aber nicht länger als 24 Stunden. Ich versuche, es in 1 Stunde zu erledigen, ohne die gesamte Tabelle zu sperren, da ich später den von dieser Tabelle abhängigen Sphinx-Index aktualisieren muss. Es spielt keine Rolle, ob die Schritte länger dauern, solange die Datenbank für andere Aufgaben verfügbar ist.
- Ich könnte das CSV-Format in einem Vorverarbeitungsschritt ändern. Das einzige, was zählt, ist ein schnelles Update und ohne Sperren.
- Tabelle 2 ist MyISAM. Dies ist die neu erstellte Tabelle aus der CSV-Datei, die die Ladedaten-Datei verwendet. MYI Dateigröße beträgt 452 MB. Tabelle 2 ist in der Spalte field1 indiziert.
- MYD der MyISAM-Tabelle ist 663 MB.
Update 3:
Hier finden Sie weitere Details zu beiden Tabellen.
CREATE TABLE `content` (
`hash` char(40) CHARACTER SET ascii NOT NULL DEFAULT '',
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`og_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`keywords` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`files_count` smallint(5) unsigned NOT NULL DEFAULT '0',
`more_files` smallint(5) unsigned NOT NULL DEFAULT '0',
`files` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0',
`category` smallint(3) unsigned NOT NULL DEFAULT '600',
`size` bigint(19) unsigned NOT NULL DEFAULT '0',
`downloaders` int(11) NOT NULL DEFAULT '0',
`completed` int(11) NOT NULL DEFAULT '0',
`uploaders` int(11) NOT NULL DEFAULT '0',
`creation_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`upload_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`last_updated` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`vote_up` int(11) unsigned NOT NULL DEFAULT '0',
`vote_down` int(11) unsigned NOT NULL DEFAULT '0',
`comments_count` int(11) NOT NULL DEFAULT '0',
`imdb` int(8) unsigned NOT NULL DEFAULT '0',
`video_sample` tinyint(1) NOT NULL DEFAULT '0',
`video_quality` tinyint(2) NOT NULL DEFAULT '0',
`audio_lang` varchar(127) CHARACTER SET ascii NOT NULL DEFAULT '',
`subtitle_lang` varchar(127) CHARACTER SET ascii NOT NULL DEFAULT '',
`verified` tinyint(1) unsigned NOT NULL DEFAULT '0',
`uploader` int(11) unsigned NOT NULL DEFAULT '0',
`anonymous` tinyint(1) NOT NULL DEFAULT '0',
`enabled` tinyint(1) unsigned NOT NULL DEFAULT '0',
`tfile_size` int(11) unsigned NOT NULL DEFAULT '0',
`scrape_source` tinyint(1) unsigned NOT NULL DEFAULT '0',
`record_num` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`record_num`),
UNIQUE KEY `hash` (`hash`),
KEY `uploaders` (`uploaders`),
KEY `tfile_size` (`tfile_size`),
KEY `enabled_category_upload_date_verified_` (`enabled`,`category`,`upload_date`,`verified`),
KEY `enabled_upload_date_verified_` (`enabled`,`upload_date`,`verified`),
KEY `enabled_category_verified_` (`enabled`,`category`,`verified`),
KEY `enabled_verified_` (`enabled`,`verified`),
KEY `enabled_uploader_` (`enabled`,`uploader`),
KEY `anonymous_uploader_` (`anonymous`,`uploader`),
KEY `enabled_uploaders_upload_date_` (`enabled`,`uploaders`,`upload_date`),
KEY `enabled_verified_category` (`enabled`,`verified`,`category`),
KEY `verified_enabled_category` (`verified`,`enabled`,`category`)
) ENGINE=InnoDB AUTO_INCREMENT=7551163 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=FIXED
CREATE TABLE `content_csv_dump_temp` (
`hash` char(40) CHARACTER SET ascii NOT NULL DEFAULT '',
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`category_id` int(11) unsigned NOT NULL DEFAULT '0',
`uploaders` int(11) unsigned NOT NULL DEFAULT '0',
`downloaders` int(11) unsigned NOT NULL DEFAULT '0',
`verified` tinyint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`hash`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
und hier ist die Aktualisierungsabfrage, die die content
Tabelle unter Verwendung von Daten aus aktualisiertcontent_csv_dump_temp
UPDATE content a JOIN content_csv_dump_temp b
ON a.hash = b.hash
SET
a.uploaders = b.uploaders,
a.downloaders = b.downloaders,
a.verified = b.verified
Update 4:
Alle oben genannten Tests wurden auf einer Testmaschine durchgeführt, aber jetzt habe ich dieselben Tests auf der Produktionsmaschine durchgeführt, und die Abfragen sind sehr schnell.
mysql> UPDATE content_test a JOIN content_csv_dump_temp b
-> ON a.hash = b.hash
-> SET
-> a.uploaders = b.uploaders,
-> a.downloaders = b.downloaders,
-> a.verified = b.verified;
Query OK, 2673528 rows affected (7 min 50.42 sec)
Rows matched: 7044818 Changed: 2673528 Warnings: 0
Ich entschuldige mich für meinen Fehler. Es ist besser, Join anstelle jedes Datensatzupdates zu verwenden. Jetzt versuche ich, mpre mit dem von rick_james vorgeschlagenen Index zu verbessern. Wird aktualisiert, sobald das Benchmarking abgeschlossen ist.
UPDATEs
. Bitte teilen Sie uns genau mit, wie die einfache Anweisung zum Aktualisieren der Tabelle aus den CSV-Daten aussieht. Dann können wir Ihnen möglicherweise dabei helfen, eine Technik zu entwickeln, die Ihren Anforderungen entspricht.
update
, und überprüfen Sie bitte aktualisierte Frage., Danke
INDEX(field2, field3, field4)
(in beliebiger Reihenfolge)? Bitte zeigen Sie unsSHOW CREATE TABLE
.