Explicación detallada del motor de almacenamiento mysql InnoDB, desde la parte inferior para ver la estructura de datos de InnoDB

InnoDB es un motor de almacenamiento que admite la seguridad de las transacciones y también es el motor de almacenamiento predeterminado para mysql. Este artículo presenta principalmente el principio de realización del formato de registro de filas de InnoDB y la página de datos desde la perspectiva de la estructura de datos, y analiza el motor de almacenamiento InnoDB desde abajo.

Introducción a InnoDB

Todo el mundo sabe que los datos en mysql se almacenan en discos físicos y el procesamiento de datos reales se realiza en la memoria. Debido a que la velocidad de lectura y escritura del disco es muy lenta, si el disco se lee y escribe con frecuencia para cada operación, el rendimiento debe ser muy bajo. Para resolver los problemas anteriores, InnoDB divide los datos en varias páginas y utiliza la página como la unidad básica de interacción entre el disco y la memoria El tamaño de página general es de 16 KB. En este caso, se lee al menos una página de datos en la memoria o se escribe una página de datos en el disco a la vez. Mejore el rendimiento reduciendo el número de interacciones entre la memoria y el disco.

De hecho, esta es esencialmente una idea típica de diseño de cachés. El diseño de cachés generales se considera básicamente desde la dimensión temporal o espacial:

Dimensión de tiempo: si se está utilizando un dato, existe una alta probabilidad de que se vuelva a utilizar en el próximo período de tiempo. Se puede considerar que el almacenamiento en caché de datos en caliente pertenece a la realización de esta idea.
Dimensión espacial: si se está utilizando un dato, existe una alta probabilidad de que los datos almacenados cerca de él se utilicen pronto. Las páginas de datos de InnoDB y el caché de páginas del sistema operativo son la encarnación de esta idea.

Formato de fila InnoDB

MySQL inserta datos en la tabla de datos en unidades de registros (una fila de datos). El método de almacenamiento de estos registros en el disco se llama formato de fila. mysql admite 4 tipos diferentes de formatos de fila: compacto, redundante (más antiguo, este artículo no lo presentará específicamente), dinámico, comprimido.

Podemos especificar el formato de fila en la declaración para crear o modificar la tabla:

CREATE TABLE nombre de tabla (información de columna) ROW_FORMAT = nombre de formato de fila
ALTER TABLE nombre de tabla ROW_FORMAT = nombre de formato de fila Por
ejemplo, queremos crear una tabla de datos record_format_demo cuyo formato de fila es Compacto y el juego de caracteres es ascii. El sql es el siguiente:

mysql> CREAR TABLA record_format_demo (
-> c1 VARCHAR (10),
-> c2 VARCHAR (10) NOT NULL,
-> c3 CHAR (10),
-> c4 VARCHAR (10)
->) CHARSET = ascii ROW_FORMAT = COMPACT;
Consulta OK, 0 filas afectadas (0.03 seg)
Supongamos que insertamos 2 filas de datos en la tabla record_format_demo:

mysql> SELECT * FROM record_format_demo;
± ----- ± ---- ± ----- ± ----- +
| c1 | c2 | c3 | c4 |
± ----- ± ---- ± ----- ± ----- +
| aaaa | bbb | cc | d |
| eeee | fff | NULL | NULL |
± ----- ± ---- ± ----- ± ----- +
2 filas en conjunto (0.00 seg)

Necesita materiales de aprendizaje para arquitectos de servidores Linux C / C ++ l más qun (812855908) para obtener (los datos incluyen C / C ++, Linux, tecnología golang, Nginx, ZeroMQ, MySQL, Redis, fastdfs, MongoDB, ZK, medios de transmisión, CDN, P2P, K8S, Docker, TCP / IP, coroutine, DPDK, ffmpeg, etc.), gratis para compartirInserte la descripción de la imagen aquí

Formato de fila COMPACTO

Inserte la descripción de la imagen aquí

Como puede verse en la figura anterior, un registro completo contiene dos partes, la información adicional registrada y los datos reales registrados.

Información adicional de registros La información adicional de
registros incluye principalmente tres tipos: lista de longitud de campo de longitud variable, lista de valores NULL e información de encabezado de registro.

Lista de longitud de campo de longitud
variable MySQL admite algunos tipos de datos de longitud variable (como VARCHAR (M), TEXT, etc.) El espacio de almacenamiento que ocupan para almacenar datos no es fijo, pero cambiará con el cambio de contenido de almacenamiento. Para describir con precisión este tipo de datos, el espacio de almacenamiento ocupado por este campo de longitud variable también debe incluir:

El contenido de los datos reales
El número de bytes ocupados
En el formato de fila compacto, la longitud de bytes ocupada por los datos reales de todos los campos de longitud variable se almacena al principio del registro, formando así una lista de longitud de campo de longitud variable, cada campo de longitud variable es El número de bytes ocupados se almacena en el orden inverso de la columna.

Tomemos la primera fila de datos en record_format_demo como ejemplo. Dado que c1, c2 y c4 se convierten todos en tipos de datos (VARCHAR (10)), la longitud de estas tres columnas debe almacenarse al principio del registro.
Inserte la descripción de la imagen aquí

Otro punto a tener en cuenta es que la lista de longitud de campo de longitud variable solo almacena la longitud ocupada por el contenido de la columna cuyo valor no es NULL, y la longitud de la columna cuyo valor es NULL no se almacena. Es decir, para el segundo registro, debido a que el valor de la columna c4 es NULL, la lista de longitud de campo de longitud variable del segundo registro solo necesita almacenar la longitud de las columnas c1 y c2.

Lista de valores NULL

Para las columnas que pueden ser NULL, para ahorrar espacio de almacenamiento, mysql no almacenará el valor NULL en la parte de datos reales del registro. En su lugar, se guardará en la lista de valores NULL en la información adicional registrada.

El método específico es contar primero las columnas que permiten el almacenamiento de valores NULL en la tabla, y luego asignar cada columna que permite el almacenamiento de valores NULL corresponder a un bit binario (1: el valor es NULL, 0: el valor no es NULL) para indicar si se deben almacenar valores NULL , Y organizado en orden inverso. MySQL estipula que la lista de valores NULL debe estar representada por un número entero de bytes. Si el número de bits binarios usados ​​no es un número entero de bytes, agregue 0 al bit superior del byte.

En correspondencia con la tabla record_format_demo, c1, c3 y c4 pueden almacenar valores NULL. El diagrama esquemático de los dos primeros registros después de completar la lista de valores NULL es así:
Inserte la descripción de la imagen aquí

Información de encabezado de
grabación La información de encabezado de grabación se compone de 5 bytes fijos (40 bits) y los diferentes bits representan significados diferentes:
Inserte la descripción de la imagen aquí
no se ampliará en detalle temporalmente.

Datos reales registrados

Además de los datos específicos de cada columna, los datos reales registrados agregarán automáticamente algunos datos de columna ocultos.
Inserte la descripción de la imagen aquí
De hecho, los nombres reales de estas columnas son en realidad: DB_ROW_ID, DB_TRX_ID, DB_ROLL_PTR, row_id, transaction_id y roll_pointer están escritos por motivos de belleza.

Solo cuando la base de datos no define una clave principal o clave única, la columna oculta row_id existirá y se utilizará como clave principal de la tabla de datos.

Debido a que la tabla record_format_demo no define una clave principal, el servidor MySQL agregará las tres columnas anteriores para cada registro. Ahora eche un vistazo a la estructura de datos de los dos registros más los datos registrados reales:Inserte la descripción de la imagen aquí

Formato de almacenamiento de columna CHAR (M)

Para las columnas de tipo CHAR (M), cuando la columna usa un juego de caracteres de longitud fija, el número de bytes ocupados por la columna no se agregará a la lista de longitud de campo de longitud variable, y si se usa un juego de caracteres de longitud variable, el El número de bytes ocupados por la columna también se agregará a la lista de longitud de campo de longitud variable.

Otra cosa a tener en cuenta es que la columna de tipo CHAR (M) del conjunto de caracteres de longitud variable requiere al menos M bytes, mientras que VARCHAR (M) no tiene este requisito. Por ejemplo, para una columna CHAR (10) que usa el juego de caracteres utf8, el rango de la longitud del byte de datos almacenado en la columna es de 10-30 bytes, incluso si almacenamos una cadena vacía en la columna, ocupará 10 Bytes.

Datos de desbordamiento de filas

VARCHAR (M) Máximo de datos que se pueden almacenar
MySQL tiene un límite en el espacio máximo de almacenamiento ocupado por un registro. Excepto por las columnas BLOB o TEXT, las palabras ocupadas por todas las demás columnas (excluyendo las columnas ocultas y la información del encabezado del registro) La longitud de la sección no puede exceder los 65535 bytes en total. No es riguroso pensar que el espacio de almacenamiento ocupado por una fila de registros mysql no puede exceder los 65535 bytes. Además de los datos de la columna en sí, estos 65535 bytes también incluyen algunos otros datos (sobrecarga de almacenamiento). Por ejemplo, para almacenar una columna de tipo VARCHAR (M), en realidad necesitamos ocupar 3 partes de espacio de almacenamiento:

Datos
reales Los datos reales ocupan la longitud del byte
identificación del valor NULL. Si la columna tiene el atributo NOT NULL, no hay espacio de almacenamiento para esta parte.
Suponiendo que varchar_size_demo tiene solo un campo de tipo VARCHAR, la ocupación máxima de este campo es 65532 bytes. Debido a que la longitud de los datos reales puede ocupar 2 bytes, la identificación del valor NULO debe ocupar 1 byte. Si la columna de tipo VARCHAR no tiene el atributo NOT NULL, solo puede almacenar hasta 65532 bytes de datos. Si la columna es un juego de caracteres ascii, el número máximo de caracteres correspondientes es 65532; si es un juego de caracteres utf8, el número máximo correspondiente de caracteres es 21844.

Desbordamiento causado por demasiados datos en el registro
Tomemos la tabla varchar_size_demo en el juego de caracteres ascii como ejemplo, inserte un registro:

mysql> CREAR TABLA varchar_size_demo (
-> c VARCHAR (65532)
->) CHARSET = ascii ROW_FORMAT = Compact;
Consulta OK, 0 filas afectadas (0.01 seg)

mysql> INSERT INTO varchar_size_demo © VALUES (REPEAT ('a', 65532));
Consulta OK, 1 fila afectada (0.00 seg)
La unidad básica de interacción disco-memoria en mysql es una página, que generalmente es de 16KB, 16384 bytes y Una fila de registros puede ocupar hasta 65535 bytes, lo que provoca la situación de que una página no pueda almacenar la siguiente fila de datos. En los formatos de fila Compacto y Redundante, para las columnas que ocupan un espacio de almacenamiento muy grande, solo una parte de los datos de la columna se almacenará en los datos reales registrados, y los datos restantes se dispersarán y almacenarán en varias otras páginas, y luego se registrarán los datos reales. La ubicación de los datos utiliza 20 bytes para almacenar las direcciones que apuntan a estas páginas, de modo que se pueda encontrar la página donde se encuentran los datos restantes, como se muestra en la figura:
Inserte la descripción de la imagen aquí

Esta situación en la que solo los primeros 768 bytes de datos de la columna y una dirección que apunta a otras páginas se almacenan en los datos reales de este registro, y luego los datos restantes se almacenan en otras páginas se denomina desbordamiento de filas, desbordamiento de almacenamiento Las páginas de 768 bytes también se denominan páginas de desbordamiento.
Inserte la descripción de la imagen aquí

Punto crítico de desbordamiento de filas

MySQL requiere que al menos dos filas de registros se almacenen en una página. Tome la tabla varchar_size_demo anterior como ejemplo. Tiene solo una columna c. Insertamos dos registros en esta tabla. ¿Cuántos bytes de datos deben insertarse al menos para que cada registro se desborde? Esto tiene que analizar cómo se usa el espacio en la página.

Además de almacenar nuestros registros, cada página también necesita almacenar información adicional, aproximadamente 132 bytes.
La información adicional requerida para cada registro es de 27 bytes.
Suponiendo que el número de bytes de datos almacenados en una columna es n, si desea asegurarse de que la columna no se desborde, debe cumplir:

132 + 2 × (27 + n) <16384
da como resultado n <8099. En otras palabras, si los datos almacenados en una columna tienen menos de 8099 bytes, la columna no se convertirá en una columna de desbordamiento. Si hay varias columnas en la tabla, este valor es menor.

Formatos de fila dinámicos y comprimidos

El formato de fila predeterminado en mysql es dinámico. Los formatos de fila dinámica y comprimida son muy similares a los formatos de fila compacta, excepto que existen diferencias en el manejo de datos de desbordamiento de fila. Los formatos de fila dinámica y comprimida no almacenarán los primeros 768 bytes de los datos registrados reales, pero almacenarán todos los bytes en otras páginas. El formato de línea comprimida utiliza algoritmos de compresión para comprimir páginas y ahorrar espacio.
Inserte la descripción de la imagen aquí

Estructura de la página de datos de InnoDB

Ya sabemos que la página es la unidad básica del espacio de almacenamiento de gestión de InnoDB, el tamaño de una página es generalmente de 16KB. InnoDB ha diseñado muchos tipos diferentes de páginas para diferentes propósitos, aquí nos enfocamos principalmente en páginas que almacenan registros de datos, que oficialmente se denominan páginas de índice. Dado que el índice aún no se ha introducido, llamémoslo la página de datos por ahora.

Vista rápida de la estructura de la página de datos

La página de datos se puede dividir en varias partes en la estructura, y diferentes partes tienen diferentes funciones, como se muestra en la siguiente figura:
Inserte la descripción de la imagen aquí

Una página de datos de InnoDB se divide en 7 partes. El contenido de estas 7 partes se describe a continuación a grandes rasgos.
Inserte la descripción de la imagen aquí

Almacenamiento de registros en la página

Los propios datos almacenados del usuario se almacenarán en los registros de usuario de acuerdo con el formato de fila correspondiente. De hecho, la página recién generada no tiene Registros de usuario. Solo cuando insertemos datos por primera vez, se asignará un espacio del tamaño de un registro de Espacio libre a Registros de usuario. Cuando se agota el espacio libre, significa que la página de datos actual también se agota.
Inserte la descripción de la imagen aquí

Para que los registros de usuario sean claros, primero debemos comprender la información del encabezado del registro antes mencionada.

Comprender la información del encabezado del registro

Primero, introduzca brevemente la descripción de cada atributo de la información del encabezado del registro:
Inserte la descripción de la imagen aquí

A continuación, tome la tabla page_demo como ejemplo e inserte algunos datos para presentar la información del encabezado del registro en detalle.

mysql> CREAR TABLA page_demo (
-> c1 INT,
-> c2 INT,
-> c3 VARCHAR (10000),
-> PRIMARY KEY (c1)
->) CHARSET = ascii ROW_FORMAT = Compact;
Consulta OK, 0 filas afectadas (0.03 seg)

mysql> INSERT INTO page_demo VALUES (1, 100, 'aaaa'), (2, 200, 'bbbb'), (3, 300, 'cccc'), (4, 400, 'dddd');
Consulta OK, 4 filas afectadas (0.00 seg)
Registros: 4 Duplicados: 0 Advertencias: 0
El formato de fila de estos 4 registros en InnoDB es el siguiente (solo se muestran el encabezado del registro y los datos reales), los datos en las columnas están todos expresados ​​en decimal:
Inserte la descripción de la imagen aquí

Contrastamos esta figura para resaltar la información detallada de varios atributos:

delete_mask: marca si se borra el registro actual, 0 significa no borrado, 1 significa borrado. Los registros no eliminados no se eliminarán del disco de inmediato, sino que se marcarán para su eliminación primero y todos los registros eliminados formarán una lista enlazada de basura. Los registros recién insertados pueden reutilizar el espacio ocupado por la lista enlazada de basura, por lo que el espacio de almacenamiento ocupado por la lista enlazada de basura también se denomina espacio reutilizable.
heap_no: Indica la posición del registro actual en esta página. Por ejemplo, las posiciones de los 4 primeros registros en esta página son 2, 3, 4 y 5 respectivamente. De hecho, InnoDB agregará automáticamente dos registros virtuales a cada página, uno es el registro más pequeño y el otro es el registro más grande. La estructura de estos dos registros es muy simple y están compuestos por una información de encabezado de registro de 5 bytes y una parte fija de tamaño de 8 bytes (de hecho, el contenido es mínimo o superior). Estos dos registros se colocan por separado en la sección Infimum + Supremum.
Inserte la descripción de la imagen aquí

Como podemos ver en la figura, los valores de heap_no del registro más pequeño y el registro más grande son 0 y 1, respectivamente, lo que significa que sus posiciones están en la parte superior.

next_record: Representa el desplazamiento de la dirección de los datos reales del registro actual a los datos reales del siguiente registro. Puede entenderse simplemente como una lista enlazada individualmente, donde el registro más pequeño es el primer registro y el último registro es el registro más grande. Para una visualización más vívida, podemos usar flechas para reemplazar el desplazamiento de la dirección en next_record:
Inserte la descripción de la imagen aquí

También se puede ver en la figura que los registros del usuario en realidad están ordenados en una lista enlazada individualmente según el tamaño de la clave primaria. Si se elimina un registro, la lista vinculada también cambiará en consecuencia. Por ejemplo, eliminamos el segundo registro:
Inserte la descripción de la imagen aquí

delete_mask
next_record
next_record

Directorio de páginas

Ya sabemos que los registros se concatenan en una lista enlazada individualmente en el orden positivo del tamaño de la clave principal en la página. ¿Qué pasa si queremos encontrar un registro específico basado en la clave principal? La forma más sencilla es recorrer la lista vinculada. Pero en el caso de una cantidad relativamente grande de datos, este método es obviamente demasiado ineficiente. Entonces mysql usa Page Directory (directorio de páginas) para resolver este problema. El principio general de Page Directory es el siguiente:

Page Directory
mysql estipula que solo puede haber 1 registro para el grupo donde se encuentra el registro más pequeño, el número de registros propiedad del grupo donde se encuentra el registro más grande solo puede estar entre 1-8 y el número de registros en el grupo restante solo puede estar en el rango Está entre 4-8.

Por ejemplo, hay 18 registros normales en la tabla page_demo actual. InnoDB los dividirá en 5 grupos. Solo hay un registro más pequeño en el primer grupo, como se muestra a continuación:

[Error en la transferencia de la imagen del enlace externo. Es posible que el sitio de origen tenga un mecanismo de enlace anti-sanguijuela. Se recomienda guardar la imagen y subirla directamente (img-ZereP94x-1596671641800) (https://chentianming11.github.io/images/mysql/page directory.webp) ]

El proceso de encontrar el registro del valor de clave principal especificado en una página de datos a través de Page Directory se divide en dos pasos:

Determine la ranura en la que se encuentra el registro por dicotomía y busque el registro con el valor de clave principal más pequeño en el grupo donde se encuentra la ranura.
Recorra cada registro del grupo en el que se encuentra la ranura mediante el atributo next_record del registro.
La optimización del rendimiento de las consultas de listas enlazadas se logra básicamente a través de la dicotomía en el pensamiento. El directorio de páginas presentado anteriormente, la tabla de omisión y el árbol de búsqueda son todos iguales.

Encabezado de página

El encabezado de página se utiliza especialmente para almacenar información de estado relacionada con las páginas de datos, como cuántos registros se han almacenado en esta página, cuál es la dirección del primer registro, cuántos espacios están almacenados en el directorio de la página, etc. Ocupación fija 56 bytes, el significado de cada parte de los atributos de bytes es el siguiente:
Inserte la descripción de la imagen aquí

Esto es solo una lista, por lo que no necesito entenderlos todos en este momento.

Encabezado de archivo (encabezado de archivo)

El encabezado de archivo se utiliza para describir información general aplicable a varias páginas y consta del siguiente contenido:
Inserte la descripción de la imagen aquí

Esto es solo una lista, por lo que no necesito entenderlos todos en este momento. Nos centramos en algunos atributos:

FIL_PAGE_SPACE_OR_CHKSUM
La suma de comprobación de la página actual (suma de comprobación). Para una cadena de bytes muy larga, podemos usar algún algoritmo para calcular un valor relativamente corto para representar esta cadena de bytes muy larga. Este valor relativamente corto se llama suma de comprobación. La suma de comprobación puede mejorar en gran medida la eficacia de la comparación de equivalentes de cadenas.
FIL_PAGE_OFFSET
Cada página tiene un número de página único, e InnoDB puede localizar una página a través del número de página.
FIL_PAGE_TYPE
representa el tipo de página actual.Como dijimos anteriormente, InnoDB divide las páginas en diferentes tipos para diferentes propósitos.
Inserte la descripción de la imagen aquí

Indica el número de página de la página anterior y siguiente de esta página.Cada página forma una lista doblemente enlazada a través de FIL_PAGE_PREV y F IL_PAGE_NEXT.
Inserte la descripción de la imagen aquí

Tráiler de archivos

La unidad básica de interacción entre la memoria y el disco en mysql es la página. Si se modifica la página en la memoria, entonces la página en la memoria se sincronizará con el disco en algún momento. Si ocurre un problema en el sistema durante el proceso de sincronización, es posible que los datos de la página en el disco no estén completamente sincronizados, es decir, se han producido páginas sucias. Para evitar este tipo de problemas, mysql agrega File Trailer al final de cada página para verificar la integridad de la página. File Trailer consta de 8 bytes:

Los primeros 4 bytes representan la suma de comprobación de la página,
esta parte corresponde a la suma de comprobación en el encabezado del archivo. Una comprensión simple es que tanto el Encabezado de archivo como el Avance de archivo tienen sumas de verificación. Si los dos son consistentes, la página de datos está completa. De lo contrario, significa que la página de datos está sucia.
Los últimos 4 bytes representan la posición de la secuencia de registro (LSN) correspondiente cuando la página se modificó por última vez.
Esta parte también sirve para verificar la integridad de la página, por lo que todavía no la entenderé en detalle.

Supongo que te gusta

Origin blog.csdn.net/qq_40989769/article/details/107841350
Recomendado
Clasificación