¿Cómo usar el retraso de inserción con el motor InnoDB y usar menos conexión para las instrucciones de inserción?


10

Estoy trabajando en una aplicación que involucra muchas escrituras de bases de datos, aproximadamente ~ 70% de inserciones y 30% de lecturas. Esta proporción también incluiría actualizaciones que considero que son una lectura y una escritura. A través de las declaraciones de inserción, varios clientes insertan datos en la base de datos a través de la siguiente declaración de inserción:

$mysqli->prepare("INSERT INTO `track` (user, uniq_name, ad_name, ad_delay_time ) values (?, ?, ?, ?)");

La pregunta es si debería usar insert_delay o mysqli_multi_query mecanismo porque la declaración de inserción utiliza ~ 100% de CPU en el servidor. Estoy usando el motor InnoDB en mi base de datos, por lo que no es posible la inserción retrasada. La inserción en el servidor es de ~ 36k / hr y 99.89% de lectura, también estoy usando la instrucción select para recuperar datos siete veces en una sola consulta , esta consulta tarda 150 segundos en ejecutarse en el servidor. ¿Qué tipo de técnica o mecanismo puedo usar para esta tarea? La memoria de mi servidor es de 2 gb, ¿debería expandir la memoria? Eche un vistazo a este problema, cualquier sugerencia me lo agradecerá.

Estructura de la mesa:

+-----------------+--------------+------+-----+-------------------+----------------+
| Field           | Type         | Null | Key | Default           | Extra          |
+-----------------+--------------+------+-----+-------------------+----------------+
| id              | int(11)      | NO   | PRI | NULL              | auto_increment |
| user            | varchar(100) | NO   |     | NULL              |                |
| uniq_name       | varchar(200) | NO   |     | NULL              |                |
| ad_name         | varchar(200) | NO   |     | NULL              |                |
| ad_delay_time   | int(11)      | NO   |     | NULL              |                |
| track_time      | timestamp    | NO   | MUL | CURRENT_TIMESTAMP |                |
+-----------------+--------------+------+-----+-------------------+----------------+

El estado actual de mi base de datos muestra 41k inserciones (escrituras), lo cual es muy lento para mi base de datos.

estado de la base de datos


¿Puede proporcionar la definición de la tabla? (todas las columnas, tipos de datos e índices)
ypercubeᵀᴹ

¿Puedes dar un breve fragmento de tu SHOW FULL PROCESSLISTcuando está tomando 100% de CPU? ¿Cuántas conexiones estás permitiendo frente a cuántas se toman durante este tiempo?
Derek Downey

Ejecute estas dos consultas: SHOW GLOBAL VARIABLES LIKE 'innodb%';y SELECT VERSION();y muestre su salida.
RolandoMySQLDBA

Proporcione el número de inserciones por segundo que está ejecutando.
dabest1

Su código es muy susceptible a la inyección de SQL. Use declaraciones preparadas y valores parametrizados.
Aaron Brown

Respuestas:


11

Como tiene más escrituras que lecturas, me gustaría recomendar lo siguiente

El ajuste decente de InnoDB sería la clave

Buffer Pool (Tamaño por innodb_buffer_pool_size )

Dado que InnoDB no es compatible con INSERT DELAYED , lo más parecido que puede hacer es INSERTAR DELAYED. Todos los DML (INSERTOS, ACTUALIZACIONES y DELETES) se almacenarían en caché en el InnoDB Buffer Pool. La información transaccional para las escrituras se escribe inmediatamente en los registros de rehacer (ib_logfile0, ib_logfile1). Las escrituras que se publican en el Grupo de búferes se vacían periódicamente de la memoria al disco a través de ibdata1 (InsertBuffer para índices secundarios, búfer de doble escritura). Cuanto más grande sea el Buffer Pool, mayor será la cantidad de INSERTs que se pueden almacenar en caché. En un sistema con 8 GB o más de RAM, use el 75-80% de la RAM como innodb_buffer_pool_size. En un sistema con muy poca RAM, 25% (para acomodar el sistema operativo).

PRECAUCIÓN: puede establecer innodb_doublewrite en 0 para acelerar aún más las escrituras, pero a riesgo de la integridad de los datos. También puede acelerar las cosas configurando innodb_flush_method en O_DIRECT para evitar el almacenamiento en caché de InnoDB en el sistema operativo.

Rehacer registros ( dimensionado por innodb_log_file_size )

De forma predeterminada, los registros de rehacer se denominan ib_logfile0 e ib_logfile1 y serían 5MB cada uno. El tamaño debe ser del 25% de innodb_buffer_pool_size. Si los registros de rehacer ya existen, agregue la nueva configuración en my.cnf, cierre mysql, elimínelos y reinicie mysql .

Buffer de registro ( dimensionado por innodb_log_buffer_size )

El búfer de registro contiene cambios en la RAM antes de enjuagarlos en los registros de rehacer. El valor predeterminado es 8M. Cuanto mayor sea el búfer de registro, menor será la E / S de disco. Tenga cuidado con las transacciones muy grandes, ya que esto puede ralentizar los COMPROMISOS por milisegundos.

Acceso a múltiples CPU

MySQL 5.5 y MySQL 5.1 InnoDB Plugin tienen configuraciones para que InnoDB Storage Engine acceda a múltiples CPU. Estas son las opciones que debe configurar:

  • innodb_thread_concurrency establece el límite superior en el número de subprocesos concurrentes que InnoDB puede mantener abiertos. Por lo general, se recomienda establecer para esto es (2 X Número de CPU) + Número de discos. El año pasado, aprendí de primera mano de la Conferencia de Percona NYC que debe establecer esto en 0 para alertar al InnoDB Storage Engine para que encuentre la mejor cantidad de subprocesos para el entorno en el que se está ejecutando.
  • innodb_concurrency_tickets establece el número de subprocesos que pueden omitir la comprobación de concurrencia con impunidad. Una vez alcanzado ese límite, la comprobación de concurrencia de subprocesos vuelve a ser la norma.
  • innodb_commit_concurrency establece el número de transacciones concurrentes que pueden confirmarse. Dado que el valor predeterminado es 0, no establecer esto permite que cualquier número de transacciones se confirme simultáneamente.
  • innodb_thread_sleep_delay establece el número de milisegundos que un subproceso InnoDB puede estar inactivo antes de volver a entrar en la cola InnoDB. El valor predeterminado es 10000 (10 segundos).
  • innodb_read_io_threads (establezca esto en 3000) e innodb_write_io_threads (establezca esto en 7000) (ambos desde MySQL 5.1.38) asignan el número especificado de hilos para lecturas y escrituras. El valor predeterminado es 4 y el máximo es 64. Establezca estos en 64. Además, establezca innodb_io_capacity en 10000.

Actualizar a MySQL 5.5

Si tiene MySQL 5.0, actualice a MySQL 5.5. Si tiene MySQL 5.1.37 o anterior, actualice a MySQL 5.5. Si tiene MySQL 5.1.38 o superior y desea permanecer en MySQL 5.1, instale el complemento InnoDB. De esa manera, puede aprovechar todas las CPU para InnoDB.


la memoria de mi servidor es de 2GB, así que de acuerdo con la memoria, configuré el grupo de búferes innodb en 500M, y los archivos de registro 25% en el grupo, también configuré el búfer de registro en 64M. Pero aún así el servidor está muy ocupado. ¿Debo actualizar la memoria? Además, mi servidor está en ubuntu de 32 bits, por lo que como máximo puedo configurar la memoria en 4 GB.
Shashank

Si el servidor es solo para MySQL (sin apache, sin PHP), entonces innodb_buffer_pool_size puede tener hasta el 75% de 2GB, que es 1536M. Si actualiza a 4GB, innodb_buffer_pool_size puede ser 3G. Los archivos de registro deben ser el 25% de la agrupación de almacenamiento intermedio como usted indicó.
RolandoMySQLDBA

El servidor está ejecutando apache2, mysql y php, ¿debería buscar la memoria de actualización en esta situación o hay alguna solución óptima, excepto el grupo de búferes innodb?
Shashank

Este tipo no está de acuerdo contigo: percona.com/blog/2008/11/21/... Difícil de discutir con Percona.
Zenexer

Rolando: sugiero que agregue a la respuesta con actualizaciones para 5.6 y 5.7. Los valores predeterminados han cambiado; otras configuraciones están disponibles; etc. Quizás incluya Percona y MariaDB y 8.0 consejos.
Rick James

2

INT (2) todavía usa 4 bytes, ¿tal vez quisiste decir TINYINT SIN FIRMAR?

¿Cuántos valores diferentes hay en setno? Si es pequeño, la CLAVE (setno) nunca se utilizará. INSERTing tiene que actualizar ese índice; quitar la CLAVE acelerará INSERTAR un poco.

CHAR (10) - ¿ flagSiempre tiene 10 caracteres de longitud? ¿Y en utf8? Quizás podría usar flag VARCHAR (10) CHARACTER SET ascii

Lote sus insertos: 100 a la vez se ejecutarán 10 veces más rápido. (Más allá de 100 se está metiendo en 'rendimientos decrecientes').

¿Cuál es el valor de la confirmación automática? ¿Estás envolviendo cada INSERTAR en COMENZAR ... COMPROMISO? ¿Cuál es el valor de innodb_flush_log_at_trx_commit?


¿Cómo consigo insertar en lote si los datos se insertan a través de una fuente externa como diferentes clientes con diferentes valores ... es confiable si utilicé: codeinsertar en los valores t_name (col1, col2, col3) (val1, val2, val3), (val1, val2, val3), (val1, val2, val3), (val1, val2, val3), (val1, val2, val3); code
Shashank

1

Establecer una cola. La aplicación escribiría en una fila de fila 1 a la vez y luego sacaría filas e insertaría en una base de datos en lote según el número de filas o la cantidad de tiempo transcurrido desde la última inserción.

He visto dónde es más rápido agrupar los insertos 10,000 a la vez, por lo que deberá realizar una prueba para encontrar un punto óptimo.

Puede crear su propio sistema de cola simple o usar uno existente. Aquí hay algunos ejemplos: HornetQ y File :: Queue . Aquí hay una publicación en SE que enumera algunas otras buenas opciones: Colas de mensajes en perl, php, python .


Estoy de acuerdo con este enfoque: estoy agregando ~ 1500 inserciones cada 5 segundos en una aplicación y es inferior al segundo. mysql parece tener algún mecanismo implementado internamente que hace que las inserciones por lotes sucedan realmente muy rápidamente.
Don Wool
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.