Hable sobre el proceso de actualización de MySQL y los datos de la tabla

Veamos primero el primer problema, la instrucción SQL se ralentiza

Análisis de causa

Una instrucción SQL es muy rápida cuando se ejecuta normalmente, pero a veces se vuelve muy lenta si no sabe lo que está pasando, y una escena así es difícil de reproducir. No solo es aleatoria, sino que también tiene una corta duración, como temblar por un momento.

Nuestra declaración de actualización habitual solo realiza la acción de escritura en disco de actualizar la página de datos de la memoria y escribir el registro de rehacer, pero las páginas sucias en la memoria deben actualizarse en el disco, es decir, la acción de vaciado. Esta descarga afectará el funcionamiento de la instrucción SQL.

Resuma la escena que desencadena el rubor:

  1.  El registro de rehacer de InnoDB está lleno . En este momento, el sistema detendrá todas las operaciones de actualización, avanzará el punto de control y dejará espacio para que el registro de rehacer continúe escribiendo. Para avanzar la posición del punto de control, es necesario vaciar el registro entre los dos puntos y todas las páginas sucias correspondientes al disco . Después de eso, desde la posición de escritura hasta el punto de control es el área del registro de rehacer que se puede escribir nuevamente. En el momento en que esto suceda, todo el sistema ya no podrá aceptar actualizaciones, todas las actualizaciones deben estar bloqueadas. Si lo mira desde el monitoreo, el número de actualizaciones caerá a 0 en este momento.
  2. La memoria del sistema es insuficiente. Cuando se necesitan nuevas páginas de memoria y la memoria no es suficiente, algunas páginas de datos deben eliminarse y la memoria se libera para otras páginas de datos. Si se eliminan las "páginas sucias", las páginas sucias deben escribirse primero en el disco. InnoDB usa un grupo de búfer para administrar la memoria. Las páginas de memoria en el grupo de búfer tienen tres estados: páginas sin usar, usadas y limpias, y páginas usadas y sucias. La estrategia de InnoDB es usar la memoria tanto como sea posible, por lo que para una biblioteca de larga duración, hay pocas páginas sin usar. Cuando la página de datos que se va a leer no está en la memoria, se debe solicitar una página de datos en el grupo de búfer. En este momento, solo la página de datos menos utilizada se puede eliminar de la memoria : si se va a eliminar una página limpia, se libera directamente para su reutilización; pero si es una página sucia, la página sucia debe vaciarse al disco Primero, se puede reutilizar después de que se convierta en una página limpia.
  3.  Cuando MySQL piensa que el sistema está "inactivo", elimina algunas "páginas sucias".
  4. Si MySQL se cierra normalmente. MySQL vaciará todas las páginas sucias de la memoria en el disco, de modo que la próxima vez que se inicie MySQL, los datos se puedan leer directamente desde el disco y la velocidad de inicio será muy rápida.

Por lo tanto, aunque el vaciado de páginas sucias es normal, las dos situaciones siguientes afectarán significativamente el rendimiento:

  • Hay demasiadas páginas sucias para eliminarlas en una consulta, lo que provocará que el tiempo de respuesta de la consulta sea significativamente mayor;
  • El registro está lleno, todas las actualizaciones están bloqueadas y el rendimiento de escritura cae a 0. Esta situación es inaceptable para empresas sensibles.

InnoDB que limpia la estrategia de control de páginas sucias

 El parámetro innodb_io_capacity le dice a InnoDB la capacidad del disco, le sugiero que establezca este valor en las IOPS del disco. Las IOPS del disco se pueden probar con la herramienta fio:

fio -filename=$filename -direct=1 -iodepth 1 -thread -rw=randrw -ioengine=psync -bs=16k -size=500M -numjobs=10 -runtime=10 -group_reporting -name=mytest 

Si el parámetro innodb_io_capacity no está configurado correctamente, si la configuración es demasiado pequeña, InnoDB piensa que la capacidad del sistema es muy pobre, por lo que el vaciado de páginas sucias es particularmente lento, incluso más lento que la generación de páginas sucias, lo que provoca la acumulación de páginas sucias, que afectan la consulta y el rendimiento de la actualización. Muestra que la velocidad de escritura de MySQL es muy lenta, el TPS es muy bajo, pero la presión IO del host de la base de datos no es grande.

Sin embargo, este parámetro solo indica la capacidad de eliminar páginas sucias, pero también debe atender las solicitudes de los usuarios. La velocidad de parpadeo de InnoDB se basa en estos dos factores: uno es la proporción de páginas sucias y el otro es la velocidad de escritura del registro de rehacer . InnoDB primero calculará dos números por separado en función de estos dos factores.

  1. El parámetro innodb_max_dirty_pages_pct es el límite superior de la proporción de páginas sucias y el valor predeterminado es 75%. InnoDB calculará un número que va de 0 a 100 en función de la proporción actual de páginas sucias (asumiendo M). El pseudocódigo para calcular este número es similar a este
    F1(M)
    {
      if M>=innodb_max_dirty_pages_pct then
          return 100;
      return 100*M/innodb_max_dirty_pages_pct;
    }
  2. Cada registro escrito por InnoDB tiene un número de serie, la diferencia entre el número de serie escrito actualmente y el número de serie correspondiente al punto de control se supone que es N. InnoDB calculará un número comprendido entre 0 y 100 basándose en este N. Esta fórmula de cálculo se puede escribir como F2 (N). El algoritmo F2 (N) es más complicado, siempre que sepa que cuanto mayor es N, mayor es el valor calculado.
  3. Finalmente, de acuerdo con los dos valores de F1 (M) y F2 (N) calculados anteriormente, tome el valor mayor como R. Luego, el motor puede multiplicar la capacidad definida por innodb_io_capacity por R% para controlar la velocidad de descarga de páginas sucias. .

Ahora sabe que InnoDB vacía las páginas sucias en segundo plano, y el proceso de eliminar las páginas sucias es escribir páginas de memoria en el disco. Por lo tanto, ya sea que su declaración de consulta requiera que se elimine una página sucia cuando se necesita memoria, o debido a la lógica de vaciar las páginas sucias, ocupará recursos de IO y puede afectar su declaración de actualización, lo que puede hacer que perciba desde el negocio lado El motivo del "temblor" de MySQL. En otras palabras, preste más atención a la proporción de páginas sucias y no permita que se acerque al 75%. La proporción de páginas sucias se obtiene a través de Innodb_buffer_pool_pages_dirty / Innodb_buffer_pool_pages_total . Para comandos específicos, consulte el siguiente código:

mysql> select VARIABLE_VALUE into @a from global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_dirty';
select VARIABLE_VALUE into @b from global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_total';
select @a/@b;

Sin embargo, otro mecanismo en MySQL puede hacer que su consulta sea más lenta: cuando se prepara para vaciar una página sucia, si la página de datos al lado de la página de datos resulta ser una página sucia, este "vecino" también se llevará consigo Flush juntos; y para cada página de datos vecina, si la página de datos adyacente todavía está sucia, también se vaciará.

En InnoDB, el parámetro innodb_flush_neighbors se usa para controlar este comportamiento. Cuando el valor es 1, habrá el mecanismo de "sentado continuo" mencionado anteriormente, y cuando el valor es 0, significa que no encuentra vecinos y se cepilla. . Esta optimización es muy significativa en la era de los discos duros mecánicos y puede reducir una gran cantidad de E / S aleatorios . Las IOPS aleatorias de un disco duro mecánico son generalmente solo unos pocos cientos.La reducción de IO aleatorias con la misma operación lógica significa que el rendimiento del sistema mejora considerablemente.

Si está utilizando un dispositivo con altas IOPS como SSD, le sugiero que establezca el valor de innodb_flush_neighbors en 0. Debido a que IOPS a menudo no es el cuello de botella en este momento, y "solo vaciarlo usted mismo" puede realizar las operaciones de vaciado necesarias más rápido y reducir el tiempo de respuesta de las sentencias SQL.

Además del control de velocidad de página sucia mencionado anteriormente, el registro de rehacer no se puede configurar demasiado pequeño . El registro de rehacer debe escribirse cada vez que se envía una transacción. Si la configuración es demasiado pequeña, se llenará pronto y la posición de escritura ha estado persiguiendo CP. En este momento, el sistema debe detener todas las actualizaciones y avanzar en el punto de control. Entonces lo que ve es que la presión del disco es muy pequeña, pero el rendimiento de la base de datos cae intermitentemente .

A continuación, veamos la segunda pregunta: si se elimina la mitad de los datos de la tabla, el tamaño del archivo de la tabla no cambia.

análisis del problema

Una tabla InnoDB contiene dos partes, a saber: definición de estructura de tabla y datos. Antes de MySQL 8.0, la estructura de la tabla se almacenaba en un archivo con el sufijo .frm . La versión MySQL 8.0 ha permitido que la definición de la estructura de la tabla se coloque en la tabla de datos del sistema .

El parámetro innodb_file_per_table puede controlar si los datos de la tabla se almacenan en el espacio de tabla compartido o en un archivo separado:

  • APAGADO significa que los datos de la tabla se colocan en el espacio de tabla compartido del sistema, es decir, junto con el diccionario de datos;
  •  ON significa que los datos de cada tabla InnoDB se almacenan en un archivo con el sufijo .ibd.

A partir de la versión de MySQL 5.6.6, su valor predeterminado es ON. Es más fácil administrar una tabla de este tipo por separado como un archivo, y cuando no necesita la tabla, el sistema eliminará el archivo directamente a través del comando drop table. Si se coloca en un espacio de tabla compartido, incluso si se elimina la tabla, el espacio no se reclamará.

Al eliminar toda la tabla, puede utilizar el comando eliminar tabla para recuperar el espacio de la tabla . Sin embargo, el escenario de eliminación de más datos que encontramos es eliminar ciertas filas . En este momento, encontramos el problema al principio de nuestro artículo: los datos de la tabla se eliminaron, pero el espacio de la tabla no se recuperó.

Proceso de eliminación de datos

Sabemos que los datos en InnoDB están organizados en una estructura de árbol B + . Queremos eliminar un registro, el motor InnoDB solo marcará este registro como eliminado , si desea insertar un registro más tarde, puede reutilizar esta posición. Sin embargo, no se reducirá el tamaño del archivo de disco .

Entonces, si eliminamos todos los registros en una página de datos, se puede reutilizar toda la página de datos . Sin embargo, la multiplexación de páginas de datos es diferente de la multiplexación de registros, porque la multiplexación de registros se limita a los datos que cumplen con las condiciones de rango, y cuando se elimina toda la página del árbol B +, se puede reutilizar en cualquier posición. .

Si la utilización de dos páginas de datos adyacentes es muy baja, el sistema fusionará los datos de estas dos páginas en una de las páginas y la otra página de datos se marcará como reutilizable. Además, ¿qué pasa si borramos los datos de toda la tabla con el comando borrar? El resultado es que todas las páginas de datos se marcarán como reutilizables. Pero en el disco, el archivo no se reducirá. En otras palabras, el espacio de tabla no se puede recuperar mediante el comando de supresión . Estos se pueden reutilizar, pero el espacio no utilizado parece "agujeros".

De hecho, no solo eliminar datos creará huecos, sino también insertar datos.

Si los datos se insertan en orden ascendente del índice , entonces el índice es compacto . Pero si los datos se insertan al azar, es posible que la página de datos del índice se divida .

Suponiendo que una determinada página de datos de un determinado índice esté llena, quiero insertar una fila de datos en el rango y tengo que solicitar una nueva página para guardar los datos. Una vez que se completa la división de la página, se deja un hueco al final de la página antigua y puede haber más de un registro con un hueco.

Además, la actualización del valor en el índice puede entenderse como eliminar un valor antiguo e insertar un nuevo valor, lo que también provocará huecos. En otras palabras, las tablas que han sufrido una gran cantidad de adiciones, eliminaciones y modificaciones pueden tener agujeros. Por lo tanto, si se pueden eliminar estos orificios, se puede lograr el propósito de reducir el espacio de la mesa.

Reconstruir tabla

Según el análisis del problema anterior, resolver el vacío puede lograr el propósito de reducir el espacio, simplemente reconstruya la mesa.

El proceso de reconstrucción de la mesa:

Cree una nueva tabla con la misma estructura que la tabla original y luego lea los datos fila por fila de la tabla de origen e insértelo en la nueva tabla en el orden de ID de clave primaria creciente. De esta forma, no hay huecos en el índice de clave principal de la tabla anterior en la tabla nueva. Obviamente, el índice de clave principal de la nueva tabla es más compacto y la utilización de las páginas de datos también es mayor . Si usamos la nueva tabla como tabla temporal, después de que los datos se importen a la nueva tabla, la nueva tabla reemplazará a la tabla anterior, desde el punto de vista del efecto, reducirá el espacio de la tabla anterior.

Puede usar el comando alter table A engine = InnoDB para reconstruir la tabla. Antes de MySQL 5.5 , el proceso de ejecución de este comando era similar al que describimos anteriormente. La diferencia es que no es necesario que usted cree esta tabla temporal. MySQL completará automáticamente las operaciones de volcado de datos, intercambio de nombres de tabla y eliminación mesas viejas.

En este proceso, el paso que lleva más tiempo es el proceso de insertar datos en la tabla temporal . Si hay nuevos datos para escribir en la tabla anterior durante este proceso, se producirán pérdidas de datos. Por lo tanto, en todo el proceso de DDL, no puede haber actualizaciones en la tabla anterior, es decir, este DDL no está en línea .

El DDL en línea introducido en la versión 5.6 de MySQL optimiza este proceso de operación.

Después de la introducción de Online DDL, el proceso de reconstrucción de la tabla:

  1. Cree un archivo temporal para escanear todas las páginas de datos de la clave principal de la tabla original;
  2. Utilice los registros de la tabla original en la página de datos para generar un árbol B + y almacenarlo en un archivo temporal;
  3. En el proceso de generar archivos temporales, registre todas las operaciones en la tabla original en un archivo de registro (registro de filas);
  4. Una vez generado el archivo temporal, aplique las operaciones del archivo de registro al archivo temporal para obtener un archivo de datos con los mismos datos lógicos que la tabla original;
  5. Reemplace los archivos de datos en la Tabla A con archivos temporales.

En circunstancias normales, se requiere el bloqueo de escritura MDL antes de DDL. La instrucción alter necesita adquirir el bloqueo de escritura MDL cuando se inicia , pero este bloqueo de escritura degenera en un bloqueo de lectura antes de que los datos se copien realmente . ¿Por qué degenerar? Para realizar en línea, el bloqueo de lectura MDL no bloqueará las operaciones de adición, eliminación y modificación. Pero no se puede desbloquear directamente para evitar que otros hilos hagan DDL en esta tabla al mismo tiempo.

Para una tabla grande, el proceso de DDL en línea que lleva más tiempo es el proceso de copiar datos a una tabla temporal. Las adiciones, eliminaciones y modificaciones se pueden aceptar durante la ejecución de este paso. Por lo tanto, en relación con todo el proceso de DDL, el tiempo de bloqueo es muy corto. Para los negocios, se puede considerar en línea.

Es necesario agregar que los métodos de reconstrucción anteriores escanearán los datos de la tabla original y construirán archivos temporales . Para tablas muy grandes, esta operación consume recursos de IO y CPU . Por lo tanto, si se trata de un servicio en línea, debe controlar cuidadosamente el tiempo de funcionamiento. Si desea una operación más segura, le recomiendo que utilice el código abierto gh-ost de GitHub.

Online 和 inplace

Hablando de Online, necesitamos aclarar la diferencia entre este y otro concepto confuso relacionado con DDL.

Como se mencionó anteriormente, antes de la versión 5.5, la reconstrucción de tablas es insertar datos en tablas temporales, y después de la versión 5.6, es poner datos en archivos temporales. Lo primero se hace en la capa del servidor y lo segundo se hace en el motor InnoDB capa.niño.

Entonces, para la capa de servidor, es una operación "en el lugar" que no mueve los datos a la tabla temporal. Esta es la fuente del nombre "en el lugar", pero los archivos temporales también ocupan espacio temporal.

La afirmación de que reconstruimos la tabla alter table t engine = InnoDB en realidad implica que alter table t engine = innodb, ALGORITHM = inplace;

Correspondiente a inplace es la forma de copiar la tabla, alterar la tabla t motor = innodb, ALGORITMO = copiar;

Cuando se usa ALGORITHM = copy, significa que la tabla está forzada a ser copiada, y el proceso correspondiente es el proceso de operación de la tabla temporal.

Hasta este punto, a primera vista, inplace también está en línea, pero de hecho, esto es solo porque la lógica de reconstrucción de la tabla está en el lugar y también pueden ser operaciones DML.

Por ejemplo, quiero agregar un índice de texto completo a un campo de una tabla InnoDB, escrito como: alter table t add FULLTEXT (field_name); este proceso está en su lugar, pero bloqueará las operaciones de adición, eliminación y modificación, y no está en línea.

La relación entre estas dos lógicas se puede resumir como:

  • Si el proceso de DDL está en línea, debe estar en su lugar;
  • Lo contrario no es necesariamente cierto, es decir, el DDL de inplace puede no estar en línea. A partir de MySQL 8.0, este es el caso con la adición del índice de texto completo (índice FULLTEXT) y el índice espacial (índice SPATIAL).

Extender, optimizar tabla, analizar tabla y alterar tabla son las tres formas de reconstruir la diferencia entre la tabla:

  • A partir de la versión 5.6 de MySQL, alter table t engine = InnoDB (es decir, recrear) tiene como valor predeterminado el proceso de almacenamiento de datos en los archivos temporales anteriores;
  • analizar la tabla t no es en realidad reconstruir la tabla, sino volver a establecer la información de índice de la tabla sin modificar los datos En este proceso se agrega el bloqueo de lectura MDL;
  • optimizar la tabla t es igual a recrear + analizar.

En cuanto a la reconstrucción de la mesa, existe un problema extremo:

A veces, el uso de alter table t engine = InnoDB aumentará el espacio ocupado por una tabla.

Motivo: al reconstruir la tabla, InnoDB no llenará toda la tabla y 1/16 de cada página se reserva para actualizaciones posteriores. En otras palabras, no es el "más" compacto después de reconstruir la tabla. Si hay una nueva operación de DML antes de reconstruir nuevamente, ocupará el espacio restante de la página. En este momento, si vuelve a encoger, continuará reservando espacio en 1/16, de modo que después de encoger, el archivo se agrandará.

Fuente del contenido: Lin Xiaobin "45 conferencias sobre combate real de MySQL"

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Supongo que te gusta

Origin blog.csdn.net/qq_24436765/article/details/112557501
Recomendado
Clasificación