Usando MySQL 5.6 con el motor de almacenamiento InnoDB para la mayoría de las tablas. El tamaño de la agrupación de almacenamiento intermedio de InnoDB es de 15 GB y los índices Innodb DB + son de alrededor de 10 GB. El servidor tiene 32 GB de RAM y ejecuta Cent OS 7 x64.
Tengo una gran tabla que contiene más de 10 millones de registros.
Recibo un archivo de volcado actualizado de un servidor remoto cada 24 horas. El archivo está en formato csv. No tengo control sobre ese formato. El archivo es ~ 750 MB. Intenté insertar datos en una tabla MyISAM fila por fila y me tomó 35 minutos.
Necesito tomar solo 3 valores por línea de 10-12 del archivo y actualizarlo en la base de datos.
¿Cuál es la mejor manera de lograr algo como esto?
Necesito hacer esto diariamente.
Actualmente Flow es así:
- mysqli_begin_transaction
- Leer archivo de volcado línea por línea
- Actualice cada registro línea por línea.
- mysqli_commit
Las operaciones anteriores tardan entre 30 y 40 minutos en completarse y, mientras lo hago, hay otras actualizaciones en curso que me dan
Tiempo de espera de bloqueo excedido; intente reiniciar la transacción
Actualización 1
carga de datos en una nueva tabla usando LOAD DATA LOCAL INFILE
. En MyISAM tardó 38.93 sec
mientras que en InnoDB tardó 7 min 5.21 sec. Entonces hice:
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)
Actualización 2
misma actualización con consulta de unión
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)
Aclaraciones de las preguntas en los comentarios:
- Alrededor del 6% de las filas de la tabla serán actualizadas por el archivo, pero a veces puede llegar hasta el 25%.
- Hay índices en los campos que se actualizan. Hay 12 índices en la tabla y 8 índices incluyen los campos de actualización.
- No es necesario hacer la actualización en una transacción. Puede llevar tiempo, pero no más de 24 horas. Estoy tratando de hacerlo en 1 hora sin bloquear toda la tabla, ya que luego tengo que actualizar el índice de esfinge que depende de esta tabla. No importa si los pasos duran más, siempre que la base de datos esté disponible para otras tareas.
- Podría modificar el formato csv en un paso de preproceso. Lo único que importa es una actualización rápida y sin bloqueo.
- La tabla 2 es MyISAM. Es la tabla recién creada del archivo csv que utiliza el archivo de datos de carga. El tamaño del archivo MYI es de 452 MB. La tabla 2 está indexada en la columna campo1.
- MYD de la tabla MyISAM es 663MB.
Actualización 3:
Aquí hay más detalles sobre ambas tablas.
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
y aquí está la consulta de actualización que actualiza la content
tabla usando datos 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
actualización 4:
todas las pruebas anteriores se realizaron en la máquina de prueba, pero ahora hice las mismas pruebas en la máquina de producción y las consultas son muy rápidas.
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
Pido disculpas por mi error. Es mejor usar join en lugar de cada actualización de registro. ahora estoy tratando de mejorar mpre usando el índice sugerido por rick_james, se actualizará una vez que se realice el benchmarking.
UPDATEs
. Díganos exactamente cómo se ve la declaración directa para actualizar la tabla a partir de los datos csv. Entonces podremos ayudarlo a diseñar una técnica que cumpla con sus requisitos.
update
, y por favor revise la pregunta actualizada. Gracias
INDEX(field2, field3, field4)
(en cualquier orden)? Por favor muéstranosSHOW CREATE TABLE
.