Utilizzo di MySQL 5.6 con motore di archiviazione InnoDB per la maggior parte delle tabelle. La dimensione del pool di buffer InnoDB è di 15 GB e gli indici Innodb DB + sono di circa 10 GB. Il server ha 32 GB di RAM ed esegue Cent OS 7 x64.
Ho un grande tavolo che contiene circa 10 milioni di record.
Ricevo un file di dump aggiornato da un server remoto ogni 24 ore. Il file è in formato CSV. Non ho il controllo su quel formato. Il file è ~ 750 MB. Ho provato a inserire i dati in una tabella MyISAM riga per riga e ci sono voluti 35 minuti.
Ho bisogno di prendere solo 3 valori per riga su 10-12 dal file e aggiornarlo nel database.
Qual è il modo migliore per ottenere qualcosa del genere?
Devo farlo ogni giorno.
Attualmente Flow è così:
- mysqli_begin_transaction
- Leggi il file di dump riga per riga
- Aggiorna ogni record riga per riga.
- mysqli_commit
Il completamento delle operazioni sopra richiede circa 30-40 minuti e, mentre lo faccio, ci sono altri aggiornamenti in corso che mi danno
Timeout attesa blocco superato; prova a riavviare la transazione
Aggiornamento 1
caricamento dei dati in una nuova tabella utilizzando LOAD DATA LOCAL INFILE
. In MyISAM ci sono voluti 38.93 sec
mentre in InnoDB ci sono voluti 7 minuti 5,21 sec. Quindi ho fatto:
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)
Aggiornamento 2
stesso aggiornamento con query di join
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)
Chiarimenti da domande nei commenti:
- Circa il 6% delle righe nella tabella verrà aggiornato dal file, ma a volte può arrivare fino al 25%.
- Ci sono indici sui campi in fase di aggiornamento. Ci sono 12 indici sulla tabella e 8 indici includono i campi di aggiornamento.
- Non è necessario eseguire l'aggiornamento in una transazione. Può richiedere del tempo ma non più di 24 ore. Sto cercando di farlo in 1 ora senza bloccare l'intera tabella, poiché in seguito devo aggiornare l'indice della sfinge che dipende da questa tabella. Non importa se i passaggi richiedono una durata maggiore purché il database sia disponibile per altre attività.
- Potrei modificare il formato CSV in una fase di preelaborazione. L'unica cosa che conta è l'aggiornamento rapido e senza blocco.
- La tabella 2 è MyISAM. È la tabella appena creata dal file CSV che utilizza il file di caricamento dei dati. La dimensione del file MYI è 452 MB. La tabella 2 è indicizzata nella colonna field1.
- MYD della tabella MyISAM è 663 MB.
Aggiornamento 3:
ecco maggiori dettagli su entrambe le tabelle.
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
e qui è la query di aggiornamento che aggiorna la content
tabella utilizzando i dati dacontent_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
aggiornamento 4:
tutti i test sopra riportati sono stati eseguiti sulla macchina di prova, ma ora ho fatto gli stessi test sulla macchina di produzione e le query sono molto veloci.
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
mi scuso per il mio errore. È meglio usare join invece di ogni aggiornamento del record. ora sto cercando di migliorare mpre usando l'indice suggerito da rick_james, aggiornerò una volta eseguito il benchmarking.
UPDATEs
. Per favore, dicci esattamente come appare l'istruzione semplice per l'aggiornamento della tabella dai dati CSV. Quindi potremmo essere in grado di aiutarti a ideare una tecnica che soddisfi le tue esigenze.
update
, e per favore controlla la domanda aggiornata., Grazie
INDEX(field2, field3, field4)
(in qualsiasi ordine)? Per favore, mostraceloSHOW CREATE TABLE
.