Esta pregunta se vuelve a publicar desde Stack Overflow en función de una sugerencia en los comentarios, disculpas por la duplicación.
Preguntas
Pregunta 1: a medida que aumenta el tamaño de la tabla de la base de datos, ¿cómo puedo ajustar MySQL para aumentar la velocidad de la llamada LOAD DATA INFILE?
Pregunta 2: ¿usaría un grupo de computadoras para cargar diferentes archivos csv, mejorar el rendimiento o matarlo? (esta es mi tarea de referencia para mañana usando los datos de carga y las inserciones masivas)
Objetivo
Estamos probando diferentes combinaciones de detectores de características y parámetros de agrupación para la búsqueda de imágenes, como resultado, necesitamos poder construir y grandes bases de datos de manera oportuna.
Información de la máquina
La máquina tiene 256 gig de ram y hay otras 2 máquinas disponibles con la misma cantidad de ram si hay una manera de mejorar el tiempo de creación mediante la distribución de la base de datos.
Esquema de tabla
el esquema de la tabla se parece
+---------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------------+------+-----+---------+----------------+
| match_index | int(10) unsigned | NO | PRI | NULL | |
| cluster_index | int(10) unsigned | NO | PRI | NULL | |
| id | int(11) | NO | PRI | NULL | auto_increment |
| tfidf | float | NO | | 0 | |
+---------------+------------------+------+-----+---------+----------------+
creado con
CREATE TABLE test
(
match_index INT UNSIGNED NOT NULL,
cluster_index INT UNSIGNED NOT NULL,
id INT NOT NULL AUTO_INCREMENT,
tfidf FLOAT NOT NULL DEFAULT 0,
UNIQUE KEY (id),
PRIMARY KEY(cluster_index,match_index,id)
)engine=innodb;
Benchmarking hasta ahora
El primer paso fue comparar las inserciones en masa frente a la carga de un archivo binario en una tabla vacía.
It took: 0:09:12.394571 to do 4,000 inserts with 5,000 rows per insert
It took: 0:03:11.368320 seconds to load 20,000,000 rows from a csv file
Dada la diferencia en el rendimiento que utilicé al cargar los datos de un archivo csv binario, primero cargué archivos binarios que contenían filas de 100K, 1M, 20M, 200M usando la siguiente llamada.
LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test;
Eliminé la carga del archivo binario de 200M filas (archivo csv ~ 3GB) después de 2 horas.
Entonces ejecuté un script para crear la tabla, e inserto diferentes números de filas de un archivo binario y luego dejo caer la tabla, vea el gráfico a continuación.
Tomó aproximadamente 7 segundos insertar 1M filas del archivo binario. A continuación, decidí hacer un benchmark insertando filas de 1M a la vez para ver si habría un cuello de botella en un tamaño de base de datos particular. Una vez que la base de datos alcanzó aproximadamente 59 millones de filas, el tiempo promedio de inserción se redujo a aproximadamente 5,000 / segundo
Establecer global key_buffer_size = 4294967296 mejoró ligeramente las velocidades para insertar archivos binarios más pequeños. El siguiente gráfico muestra las velocidades para diferentes números de filas
Sin embargo, para insertar filas de 1M no mejoró el rendimiento.
filas: 1,000,000 de tiempo: 0: 04: 13.761428 insertos / seg: 3,940
vs para una base de datos vacía
filas: 1,000,000 de tiempo: 0: 00: 6.339295 insertos / seg: 315,492
Actualizar
Hacer los datos de carga usando la siguiente secuencia versus simplemente usando el comando cargar datos
SET autocommit=0;
SET foreign_key_checks=0;
SET unique_checks=0;
LOAD DATA INFILE '/mnt/imagesearch/tests/eggs.csv' INTO TABLE test_ClusterMatches;
SET foreign_key_checks=1;
SET unique_checks=1;
COMMIT;
Por lo tanto, esto parece bastante prometedor en términos del tamaño de la base de datos que se está generando, pero las otras configuraciones no parecen afectar el rendimiento de la llamada de archivo de datos de carga.
Luego intenté cargar varios archivos desde diferentes máquinas, pero el comando de carga de archivos de datos bloquea la tabla, debido al gran tamaño de los archivos que hace que las otras máquinas agoten el tiempo de espera.
ERROR 1205 (HY000) at line 1: Lock wait timeout exceeded; try restarting transaction
Aumentar el número de filas en archivo binario
rows: 10,000,000 seconds rows: 0:01:36.545094 inserts/sec: 103578.541236
rows: 20,000,000 seconds rows: 0:03:14.230782 inserts/sec: 102970.29026
rows: 30,000,000 seconds rows: 0:05:07.792266 inserts/sec: 97468.3359978
rows: 40,000,000 seconds rows: 0:06:53.465898 inserts/sec: 96743.1659866
rows: 50,000,000 seconds rows: 0:08:48.721011 inserts/sec: 94567.8324859
rows: 60,000,000 seconds rows: 0:10:32.888930 inserts/sec: 94803.3646283
Solución: precomputar la identificación fuera de MySQL en lugar de usar el incremento automático
Construyendo la mesa con
CREATE TABLE test (
match_index INT UNSIGNED NOT NULL,
cluster_index INT UNSIGNED NOT NULL,
id INT NOT NULL ,
tfidf FLOAT NOT NULL DEFAULT 0,
PRIMARY KEY(cluster_index,match_index,id)
)engine=innodb;
con el SQL
LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';"
Hacer que el script precalcule los índices parece haber eliminado el impacto en el rendimiento a medida que la base de datos crece en tamaño.
Actualización 2 - usando tablas de memoria
Aproximadamente 3 veces más rápido, sin tener en cuenta el costo de mover una tabla en memoria a una tabla basada en disco.
rows: 0 seconds rows: 0:00:26.661321 inserts/sec: 375075.18851
rows: 10000000 time: 0:00:32.765095 inserts/sec: 305202.83857
rows: 20000000 time: 0:00:38.937946 inserts/sec: 256818.888187
rows: 30000000 time: 0:00:35.170084 inserts/sec: 284332.559456
rows: 40000000 time: 0:00:33.371274 inserts/sec: 299658.922222
rows: 50000000 time: 0:00:39.396904 inserts/sec: 253827.051994
rows: 60000000 time: 0:00:37.719409 inserts/sec: 265115.500617
rows: 70000000 time: 0:00:32.993904 inserts/sec: 303086.291334
rows: 80000000 time: 0:00:33.818471 inserts/sec: 295696.396209
rows: 90000000 time: 0:00:33.534934 inserts/sec: 298196.501594
cargando los datos en una tabla basada en memoria y luego copiándolos en una tabla basada en disco en fragmentos tuvo una sobrecarga de 10 min 59.71 segundos para copiar 107,356,741 filas con la consulta
insert into test Select * from test2;
lo que hace que sea aproximadamente 15 minutos cargar filas de 100M, que es aproximadamente lo mismo que insertarlo directamente en una tabla basada en disco.
id
debería ser más rápido. (Aunque creo que no estás buscando esto)Respuestas:
Buena pregunta, bien explicada.
Ya tiene una configuración alta (ish) para el búfer de claves, pero ¿es suficiente? Supongo que se trata de una instalación de 64 bits (si no, lo primero que debe hacer es actualizar) y no ejecutarse en MSNT. Eche un vistazo a la salida de mysqltuner.pl después de ejecutar algunas pruebas.
Para utilizar el caché para obtener el mejor efecto, puede encontrar beneficios al agrupar / ordenar previamente los datos de entrada (las versiones más recientes del comando 'ordenar' tienen mucha funcionalidad para ordenar grandes conjuntos de datos). Además, si genera los números de identificación fuera de MySQL, entonces puede ser más eficiente.
Suponiendo (nuevamente) que desea que el conjunto de salida se comporte como una sola tabla, entonces los únicos beneficios que obtendrá serán al distribuir el trabajo de ordenar y generar identificadores, para lo cual no necesita más bases de datos. OTOH usando un clúster de base de datos, obtendrá problemas con la contención (que no debería ver más que como problemas de rendimiento).
Si puede fragmentar los datos y manejar los conjuntos de datos resultantes de forma independiente, entonces sí, obtendrá beneficios de rendimiento, pero esto no elimina la necesidad de ajustar cada nodo.
Comprueba que tienes al menos 4 Gb para sort_buffer_size.
Más allá de eso, el factor limitante en el rendimiento se trata de E / S de disco. Hay muchas maneras de abordar esto, pero probablemente debería considerar un conjunto reflejado de conjuntos de datos seccionados en SSD para un rendimiento óptimo.
fuente
load data...
es más rápido que insertar, así que úsalo.Si desea ser realmente elegante, puede crear un programa multiproceso para alimentar un solo archivo a una colección de canalizaciones con nombre y administrar las instancias de inserción.
En resumen, no ajusta MySQL para esto tanto como ajusta su carga de trabajo a MySQL.
fuente
No recuerdo exactamente la sintaxis, pero si es inob, puede desactivar la verificación de clave externa.
También puede crear el índice después de la importación, puede ser realmente una ganancia de rendimiento.
fuente