Utiliser MySQL 5.6 avec le moteur de stockage InnoDB pour la plupart des tables. La taille du pool de mémoire tampon InnoDB est de 15 Go et les index Innodb DB + d'environ 10 Go. Le serveur dispose de 32 Go de RAM et exécute Cent OS 7 x64.
J'ai une grande table qui contient environ 10 millions de disques.
Je reçois un fichier de vidage mis à jour d'un serveur distant toutes les 24 heures. Le fichier est au format csv. Je n'ai pas de contrôle sur ce format. Le fichier est ~ 750 MB. J'ai essayé d'insérer des données dans une table MyISAM ligne par ligne et cela a pris 35 minutes.
Je dois prendre seulement 3 valeurs par ligne sur 10-12 du fichier et le mettre à jour dans la base de données.
Quel est le meilleur moyen de réaliser quelque chose comme ça?
J'ai besoin de faire ça tous les jours.
Actuellement, Flow est comme ça:
- mysqli_begin_transaction
- Lire le fichier de vidage ligne par ligne
- Mettez à jour chaque enregistrement ligne par ligne.
- mysqli_commit
Les opérations ci-dessus prennent environ 30 à 40 minutes et, ce faisant, d’autres mises à jour sont en cours, ce qui me permet
Délai d'attente de verrouillage dépassé; essayez de redémarrer la transaction
Mise à jour 1
Chargement des données dans une nouvelle table avec LOAD DATA LOCAL INFILE
. Dans MyISAM, il a 38.93 sec
fallu 7 minutes à 5,21 secondes pour se rendre à InnoDB. Puis j'ai fait:
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)
Mise à jour 2
même mise à jour avec requête de jointure
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)
Clarifications des questions dans les commentaires:
- Environ 6% des lignes de la table seront mises à jour par le fichier, mais cela peut parfois atteindre 25%.
- Il y a des index sur les champs en cours de mise à jour. La table contient 12 index et 8 index incluent les champs de mise à jour.
- Il n'est pas nécessaire de faire la mise à jour en une seule transaction. Cela peut prendre du temps mais pas plus de 24 heures. Je cherche à le faire en 1 heure sans verrouiller l'ensemble de la table, car je devrai ensuite mettre à jour l'index sphinx, qui dépend de cette table. Peu importe si les étapes durent plus longtemps tant que la base de données est disponible pour d'autres tâches.
- Je pourrais modifier le format CSV dans une étape de prétraitement. La seule chose qui compte est la mise à jour rapide et sans verrouillage.
- Le tableau 2 est MyISAM. C'est la table nouvellement créée à partir d'un fichier csv utilisant load data infile. La taille du fichier MYI est de 452 Mo. Le tableau 2 est indexé sur la colonne champ1.
- MYD de la table MyISAM est de 663 Mo.
Mise à jour 3:
voici plus de détails sur les deux tables.
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
et voici la requête de mise à jour qui met à jour la content
table en utilisant les données decontent_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
mise à jour 4:
Tous les tests ci-dessus ont été effectués sur une machine de test., mais maintenant, j'ai effectué les mêmes tests sur la machine de production et les requêtes sont très rapides.
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
Je m'excuse pour mon erreur. Il est préférable d’utiliser join au lieu de chaque mise à jour d’enregistrement. Maintenant, j'essaye d'améliorer mpre en utilisant l'index suggéré par rick_james, je le mettrai à jour une fois le benchmark terminé.
UPDATEs
. Dites-nous exactement à quoi ressemble une déclaration simple pour la mise à jour de la table à partir des données CSV. Ensuite, nous pourrons peut-être vous aider à concevoir une technique qui réponde à vos exigences.
update
, et s'il vous plaît vérifier la question mise à jour., Merci
INDEX(field2, field3, field4)
(dans n'importe quel ordre)? S'il vous plaît nous montrerSHOW CREATE TABLE
.