2010-10-17 17 views
9

Tengo una aplicación que necesita actualizar una gran cantidad de datos en un gran número de entradas. Básicamente, realiza unas 7.000 inserciones y/o actualizaciones, pero lleva mucho tiempo (como casi 9 minutos ... con un promedio de aproximadamente 0,08 segundos por consulta). Básicamente, estoy buscando aceleraciones generales para hacer múltiples solicitudes de este tipo (no espero una respuesta específica a mi vago ejemplo ... eso es solo para, afortunadamente, ayudar a explicarlo).Acelerando un gran número de actualizaciones e inserciones de mysql

He aquí algunos ejemplos de perfiles de las solicitudes:

SELECT `habitable_planets`.* FROM `habitable_planets` WHERE (timestamp = '2010-10-15T07:30:00-07:00') AND (planet_id = '2010_Gl_581_c') 

INSERT INTO `habitable_planets` (`planet_id`, `timestamp`, `weather_air_temp`, `weather_cell_temp`, `weather_irradiance`, `weather_wind_float`, `biolumin_to_date`, `biolumin_detected`, `craft_energy_usage`, `craft_energy_consumed_to_date`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 

SELECT `habitable_planets`.* FROM `habitable_planets` WHERE (timestamp = '2010-10-15T07:45:00-07:00') AND (planet_id = '2010_Gl_581_c') 

INSERT INTO `habitable_planets` (`planet_id`, `timestamp`, `weather_air_temp`, `weather_cell_temp`, `weather_irradiance`, `weather_wind_float`, `biolumin_to_date`, `biolumin_detected`, `craft_energy_usage`, `craft_energy_consumed_to_date`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 

Repetir hasta la saciedad (así, alrededor de 7.000 veces). Esta es una actualización que recopila los datos generados a intervalos durante un período de 24 horas y luego realiza una actualización masiva de la base de datos una vez al día. Dado el poco tiempo que le he mostrado, ¿hay alguna sugerencia para acelerar este proceso?

Por ejemplo ... ¿tendría sentido, en lugar de hacer una selección para cada marca de tiempo, hacer una selección para un rango de una vez y luego iterar sobre ellas en el script?

vagamente a:

SELECT `habitable_planets`.* FROM `habitable_planets` WHERE (planet_id = '2010_Gl_581_c') 

asignar el resultado a $foo y luego hacer:

foreach ($foo as $bar) 
{ 
    if ($bar['timestamp'] == $baz) // where $baz is the needed timestamp 
    { 
    // do the insert here 
    } 
} 

EDIT: Para añadir un poco de esto, una cosa que ha mejorado la capacidad de respuesta en mi situación era para cambiar un montón de código que comprobó la existencia de un registro existente y, o bien realizó una inserción o una actualización según el resultado en el uso de una consulta INSERT... ON DUPLICATE KEY UPDATE sql. Esto dio como resultado una ganancia de velocidad de aproximadamente 30% en mi caso particular porque cortó al menos un viaje a la base de datos fuera de la ecuación y sobre miles de solicitudes esto realmente se suma.

Respuesta

16

Algunos enlaces útiles:

Desde MySQL Documentación:

Speed of INSERT Statements dice:

  • Si va a insertar tantas filas desde el mismo cliente al mismo tiempo, el uso instrucciones INSERT con múltiples valores listas para insertar varias filas a la vez . Esto es considerablemente más rápido (muchas veces más rápido en algunos casos) que usando instrucciones separadas INSERT de una sola fila. Si está agregando datos a una tabla no vacía, puede sintonizar la variable bulk_insert_buffer_size a hacer que la inserción de datos sea aún más rápida.

  • Si varios clientes están insertando muchas filas, puede obtener una velocidad más alta utilizando la instrucción INSERT DELAYED.

  • Para una tabla MyISAM, puede usar inserciones concurrentes para agregar filas al mismo tiempo que SELECCIONAR declaraciones son correr, si no hay filas eliminadas en medio del archivo de datos.

  • Al cargar una tabla desde un archivo de texto, use LOAD DATA INFILE. Esto es por lo general 20 veces más rápido que el uso de declaraciones INSERT.

  • Con un poco de trabajo extra, es posible hacer que LOAD DATA INFILE correr aún más rápido para una tabla MyISAM cuando la mesa tiene muchos índices.

+1

+1. Buena respuesta completa. – sberry

2

Si aún no se encuentra, usar comandos preparados (ya sea a través mysqli, PDO, o alguna otra biblioteca de base de datos compatible con ellas). Reutilizar la misma declaración preparada y simplemente cambiar los valores de los parámetros ayudará a agilizar las cosas, ya que el servidor MySQL solo tiene que analizar la consulta una vez.

INSERT s se pueden agrupar proporcionando múltiples conjuntos de VALUES - una sola consulta que inserta muchas filas es mucho más rápida que un número equivalente de consultas individuales, cada una de las cuales inserta una fila.

2

Lo que sugiere es correcto. Intente reducir la cantidad de consultas que envía al servidor, ya que esto le evitará los múltiples gastos de comunicación.

Por supuesto, si la consulta de selección inicial a distancia devuelve demasiados datos, entonces puede tener un cuello de botella en PHP.

1

Probablemente usaré un procedimiento almacenado si es posible y solo lo llamaré desde el código de mi aplicación. Además, estaría pensando en una indexación adecuada y posiblemente agregue una clave sustituta de reemplazo basada en enteros para planet_id, ya que una clave de caracteres de 13 bytes no va a tener el mismo rendimiento en las uniones y búsquedas que en un entero de 4 bytes.

(acabo de leer que no se estima que hay 10 millones de billones de planetas habitables en el universo así que tal vez es mejor utilizar BIGINT sin signo: P)

drop procedure if exists update_insert_habitable_planets; 

delimiter # 

create procedure update_insert_habitable_planets 
(
in p_planet_id int unsigned, 
in p_timestamp datetime, 
) 
proc_main:begin 

    start transaction; 

    -- bulk update/insert whatever 

    commit; 

end proc_main # 

delimiter ; 
+0

* "10 millones de billones" * - 10 quintillones :) – BadHorsie

Cuestiones relacionadas