Comprensión del índice y la optimización de MySQL

Escrito al frente: los índices tienen un impacto crucial en la velocidad de las consultas, y comprender los índices también es el punto de partida para ajustar el rendimiento de la base de datos. Considere la siguiente situación, suponga que una tabla en la base de datos tiene 10 ^ 6 registros, el tamaño de página del DBMS es 4K y se almacenan 100 registros. Si no hay un índice, la consulta escaneará toda la tabla. En el peor de los casos, si todas las páginas de datos no están en la memoria, es necesario leer 10 ^ 4 páginas. Si estas 10 ^ 4 páginas se distribuyen al azar en el disco, deben leerse 10 ^ 4 E / S, asumiendo que el tiempo de E / S del disco es de 10 ms cada vez (ignorando el tiempo de transmisión de datos), tomará 100 segundos en total (pero en realidad mucho mejor). Si crea un índice B-Tree para él, solo necesita realizar log100 (10 ^ 6) = 3 lecturas de página, lo que toma 30 ms en el peor de los casos. Este es el efecto que trae el índice En muchos casos, cuando su aplicación es lenta para realizar consultas SQL, debe pensar si puede construir un índice. En el título:

Capítulo 1. Indexación y optimización

Comprensión de la explicación en video de MySQL de indexación y optimización: https://www.bilibili.com/video/BV1uz4y1671b/

1. Seleccione el tipo de datos del índice.

MySQL admite muchos tipos de datos, y elegir el tipo de datos correcto para almacenar datos tiene un gran impacto en el rendimiento. En términos generales, se pueden seguir las siguientes pautas:

(1) Los tipos de datos más pequeños suelen ser mejores: los tipos de datos más pequeños generalmente requieren menos espacio en el disco, la memoria y la memoria caché de la CPU, y son más rápidos de procesar.

(2) Los tipos de datos simples son mejores: los datos enteros tienen menos sobrecarga de procesamiento que los caracteres, porque la comparación de cadenas es más complicada. En MySQL, debe usar los tipos de datos de fecha y hora integrados en lugar de cadenas para almacenar la hora; y usar tipos de datos enteros para almacenar direcciones IP.

(3) Intente evitar NULL: debe especificar la columna como NOT NULL, a menos que desee almacenar NULL. En MySQL, las columnas con valores nulos son difíciles de consultar porque hacen que los índices, las estadísticas de índices y las operaciones de comparación sean más complicadas. Debe reemplazar el valor nulo con 0, un valor especial o una cadena vacía.

1.1, seleccione identificador

Elegir el identificador correcto es muy importante. Al elegir, no solo debe considerar el tipo de almacenamiento, sino también cómo MySQL realiza operaciones y comparaciones. Una vez que se selecciona el tipo de datos, debe asegurarse de que todas las tablas relacionadas utilicen el mismo tipo de datos.

(1) Entero: Por lo general, la mejor opción como identificador, ya que se puede procesar más rápido y se puede establecer en AUTO_INCREMENT.

(2) Cadenas: Trate de evitar el uso de cadenas como identificadores, ya que consumen más espacio y son más lentas de procesar. Además, en términos generales, las cadenas son aleatorias, por lo que sus posiciones en el índice también son aleatorias, lo que provocará divisiones de página, acceso aleatorio al disco y divisiones de índices agrupados (para motores de almacenamiento que utilizan índices agrupados).

2. Introducción a la indexación

Para cualquier DBMS, el índice es el factor más importante para la optimización. Para una pequeña cantidad de datos, el impacto de no tener un índice adecuado no es grande, pero a medida que aumenta la cantidad de datos, el rendimiento caerá drásticamente.

Si indexa varias columnas (índices compuestos), el orden de las columnas es muy importante y MySQL solo puede realizar una búsqueda efectiva en el prefijo más a la izquierda del índice. P.ej:

Suponiendo que hay un índice compuesto it1c1c2 (c1, c2), la instrucción de consulta select * from t1 donde c1 = 1 y c2 = 2 pueden usar este índice. La instrucción de consulta select * from t1 donde c1 = 1 también puede usar este índice. Sin embargo, la instrucción de consulta select * from t1 donde c2 = 2 no puede usar el índice porque no hay una columna inicial del índice compuesto, es decir, si desea usar la columna c2 para la búsqueda, c1 debe ser igual a un cierto valor .

El contenido más interesante para el desarrollo de servidores C / C ++ Linux incluye: C / C ++, Linux, Nginx, ZeroMQ, MySQL, Redis, MongoDB, ZK, transmisión de medios, P2P, kernel de Linux, Docker, TCP / IP, coroutine, DPDK Sharing de múltiples puntos de conocimiento avanzado. Haga clic en el enlace para suscribirse y verlo directamente: https://ke.qq.com/course/417774?flowToken=1013189

2.1, el tipo de índice

El índice se implementa en el motor de almacenamiento, no en la capa del servidor. Por lo tanto, los índices de cada motor de almacenamiento no son necesariamente los mismos y no todos los motores de almacenamiento admiten todos los tipos de índices.

2.1.1, índice de árbol B

Suponga que hay una tabla como sigue:

El índice contiene las columnas last_name, first_name y dob de cada fila de la tabla. Su estructura es aproximadamente la siguiente:

Los valores almacenados en el índice están ordenados en la columna de índice. Puede usar el índice B-Tree para consultar las palabras clave completas, los rangos de palabras clave y los prefijos de palabras clave. Por supuesto, si desea usar el índice, debe asegurarse de consultar por el prefijo más a la izquierda del índice.

(1) Coincidir con el valor completo: asigne valores específicos a todas las columnas del índice. Por ejemplo, el índice de la imagen de arriba puede ayudarlo a encontrar a Cuba Allen, que nació el 01-01-1960.

(2) Coincidir con un prefijo más a la izquierda: puede usar el índice para encontrar la persona cuyo apellido es Allen, usando solo la primera columna del índice.

(3) Coincidir con un prefijo de columna: por ejemplo, puede usar el índice para buscar personas cuyo apellido comience con J. Esto solo usa la primera columna del índice.

(4) Coincidir con un rango de valores: puede usar el índice para buscar personas cuyo apellido esté entre Allen y Barrymore, usando solo la primera columna del índice.

(5) Haga coincidir una parte exactamente y haga coincidir un rango en otra parte (Haga coincidir una parte exactamente y haga coincidir un rango en otra parte): Puede usar el índice para buscar personas cuyo apellido sea Allen y cuyo nombre comience con la letra K .

(6) Consultas de solo índice: si todas las columnas de consulta están ubicadas en el índice, no es necesario leer el valor de la tupla.

Dado que los nodos en el árbol B se almacenan secuencialmente, el índice se puede usar para buscar (encontrar ciertos valores), y el resultado de la consulta también se puede ordenar por. Por supuesto, el uso del índice de árbol B tiene las siguientes limitaciones:

(1) La consulta debe comenzar desde la columna más a la izquierda del índice. Este punto se ha mencionado muchas veces. Por ejemplo, no puede utilizar el índice para buscar personas que nacieron en un día determinado.

(2) No se puede omitir una columna de índice. Por ejemplo, no puede utilizar el índice para buscar personas cuyo apellido sea Smith y que hayan nacido en un día determinado.

(3) El motor de almacenamiento no puede utilizar la columna a la derecha de la condición de rango en el índice. Por ejemplo, si su consulta es WHERE last_name = "Smith" AND first_name LIKE'J% 'AND dob =' 1976-12-23 ', la consulta solo usará las dos primeras columnas del índice, porque LIKE es una consulta de rango .

2.1.2, índice hash

En MySQL, solo el motor de almacenamiento de memoria muestra que admite índices hash, que es el tipo de índice predeterminado para las tablas de memoria, aunque las tablas de memoria también pueden usar índices B-Tree. El motor de almacenamiento de memoria admite índices hash no únicos, que son raros en el campo de la base de datos. Si varios valores tienen el mismo código hash, el índice guarda sus punteros de fila en la misma entrada hash en una lista vinculada.

Suponga que crea la siguiente tabla:

Los datos incluidos son los siguientes:

Suponga que el índice usa la función hash f (), como sigue:

En este momento, la estructura del índice es aproximadamente la siguiente:

Los espacios están en orden, pero los registros no están en orden.

Cuando ejecutas mysql> SELECCIONA lname FROM testhash DONDE fname = 'Peter';

MySQL calculará el valor hash de 'Peter' y luego lo usará para consultar el puntero de fila indexado. Dado que f ('Peter') = 8784, MySQL buscará 8784 en el índice y obtendrá un puntero al registro 3.

Debido a que el índice en sí solo almacena valores cortos, el índice es muy compacto. El valor hash no depende del tipo de datos de la columna. El índice de una columna TINYINT es tan grande como el índice de una columna de cadena larga.

El índice hash tiene las siguientes limitaciones:

(1) Dado que el índice solo contiene código hash y puntero de registro, MySQL no puede evitar leer registros utilizando el índice. Pero el acceso a los registros en la memoria es muy rápido y no tendrá mucho impacto en el sexo.

(2) No se puede utilizar el índice hash para ordenar.

(3) El índice hash no admite la coincidencia parcial de claves, porque el valor hash se calcula a través de todo el valor del índice.

(4) El índice hash solo admite la comparación de equivalencia, como usar =, IN () y <=>. Para DONDE precio> 100 no acelera la consulta.

2.1.3 Índice espacial (R-Tree) MyISAM admite el índice espacial, que se utiliza principalmente para tipos de datos geoespaciales, como GEOMETRÍA.

2.1.4, índice de texto completo

El índice de texto completo es un tipo de índice especial de MyISAM, que se utiliza principalmente para la búsqueda de texto completo.

3. Estrategia de indexación de alto rendimiento

3.1, índices agrupados (índices agrupados)

El índice agrupado garantiza que la ubicación física de las tuplas con valores clave similares también sea la misma (por lo que el tipo de cadena no es adecuado para establecer un índice agrupado, especialmente cadenas aleatorias, lo que hará que el sistema realice una gran cantidad de operaciones), y una tabla solo puede Hay un índice agrupado. Dado que el motor de almacenamiento implementa el índice, no todos los motores admiten índices agrupados. Actualmente, solo es compatible con solidDB e InnoDB. La estructura de un índice agrupado es aproximadamente la siguiente:

Nota: Las páginas hoja contienen tuplas completas, mientras que las páginas de los nodos internos solo contienen columnas indexadas (las columnas indexadas son números enteros). Algunos DBMS permiten a los usuarios especificar índices agrupados, pero el motor de almacenamiento de MySQL no lo admite hasta ahora. InnoDB crea un índice agrupado en la clave principal. Si no especifica una clave principal, InnoDB utilizará un índice con un valor único y no nulo en su lugar. Si no existe tal índice, InnoDB definirá una clave primaria oculta y luego construirá un índice agrupado en ella. En términos generales, DBMS almacenará datos reales en forma de índice agrupado, que es la base de otros índices secundarios.

3.1.1. Comparación del diseño de datos InnoDB y MyISAM

Para comprender mejor el índice agrupado y el índice no agrupado, o el índice principal y el segundo índice (MyISAM no admite el índice agrupado), comparemos el diseño de datos de InnoDB y MyISAM. Para la siguiente tabla:

Suponiendo que el valor de la clave principal está entre 1 y 10,000, y se inserta en orden aleatorio, use OPTIMIZE TABLE para optimizar. A col2 se le asigna aleatoriamente un valor entre 1 y 100, por lo que habrá muchos valores duplicados.

(1) Diseño de datos de MyISAM

El diseño es muy simple, MyISAM almacena datos en el disco en el orden de inserción, de la siguiente manera:

Nota: La izquierda es el número de fila, comenzando desde 0. Debido a que el tamaño de la tupla es fijo, MyISAM puede encontrar fácilmente la posición de un determinado byte desde el principio de la tabla.

De acuerdo con la estructura del índice de clave primaria establecida, es aproximadamente la siguiente:

Nota: MyISAM no admite índices agrupados. Cada nodo hoja en el índice solo contiene un número de fila y los nodos hoja se almacenan en el orden de col1.

Eche un vistazo a la estructura del índice de col2:

De hecho, en MyISAM, la clave principal no es diferente de otros índices. La clave primaria es solo un índice único, no vacío, llamado PRIMARIO.

(2) Diseño de datos InnoDB

InnoDB almacena datos en forma de índice agrupado, por lo que su diseño de datos es muy diferente. La estructura de su mesa de almacenamiento es aproximadamente la siguiente:

Nota: Cada nodo hoja en el índice agrupado contiene el valor de la clave principal, el ID de transacción y el puntero de reversión (puntero de reversión), para transacciones y MVCC, y las columnas restantes (como col2).

En comparación con MyISAM, los índices secundarios son muy diferentes de los índices agrupados. La hoja del índice secundario de InnoDB contiene el valor de la clave principal en lugar de los punteros de fila. Esto reduce la sobrecarga de mantener el índice secundario cuando los datos se mueven o las páginas de datos se dividen, porque InnoDB no necesita actualizar el puntero de fila del índice. Su estructura es aproximadamente la siguiente:

Comparación de índice agrupado y tabla de índice no agrupado:

3.1.2, insertar filas en el orden de la clave principal (InnoDB)

Si usa InnoDB y no necesita un índice agrupado especial, una buena práctica es usar una clave sustituta independiente de los datos de su aplicación. La forma más sencilla es utilizar una columna AUTO_INCREMENT, que garantizará que los registros se inserten en orden y pueda mejorar el rendimiento de la consulta utilizando la clave principal para conectarse. Debe intentar evitar el agrupamiento aleatorio de claves primarias, por ejemplo, la clave primaria de cadena es una mala elección, hace que las operaciones de inserción se vuelvan aleatorias.

3.2, índices de cobertura

Si el índice contiene todos los datos que satisfacen la consulta, se denomina índice de cobertura. El índice de cobertura es una herramienta muy poderosa que puede mejorar en gran medida el rendimiento de las consultas. Solo la necesidad de leer el índice sin leer los datos tiene las siguientes ventajas:

(1) Los elementos del índice suelen ser más pequeños que los registros, por lo que MySQL accede a menos datos;

(2) Los índices se almacenan en orden de valor, lo que requiere menos E / S en comparación con los registros de acceso aleatorio;

(3) La mayoría de los motores de datos pueden almacenar en caché mejores índices. Por ejemplo, MyISAM solo almacena en caché los índices.

(4) Los índices de cobertura son especialmente útiles para las tablas InnoDB, ya que InnoDB utiliza índices agrupados para organizar los datos. Si el índice secundario contiene los datos necesarios para la consulta, ya no es necesario buscar en el índice agrupado.

El índice de cobertura no puede ser ningún índice, solo el índice B-TREE almacena el valor correspondiente. Y los diferentes motores de almacenamiento implementan índices de cobertura de diferentes maneras, y no todos los motores de almacenamiento admiten índices de cobertura (Memory y Falcon no lo hacen).

Para consultas cubiertas por índices, puede ver "Usar índice" en la columna Extra cuando usa EXPLAIN. Por ejemplo, en la tabla de inventario de Sakila, hay un índice compuesto (store_id, film_id). Para consultas que solo necesitan acceder a estas dos columnas, MySQL puede usar el índice, de la siguiente manera:

En la mayoría de los motores, el índice solo cubrirá cuando la columna a la que accede la consulta sea parte del índice. Sin embargo, InnoDB no se limita a esto, el índice secundario de InnoDB almacena el valor de la clave primaria en el nodo hoja. Por lo tanto, la tabla sakila.actor usa InnoDB, y hay un índice en last_name, por lo que el índice puede cubrir aquellas consultas que acceden a actor_id, tales como:

3.3, use el índice para ordenar

En MySQL, hay dos formas de generar un conjunto de resultados ordenado: una es usar filesort y la otra es escanear en orden de índice. Las operaciones de clasificación que utilizan índices son muy rápidas y el mismo índice se puede utilizar para las operaciones de búsqueda y clasificación al mismo tiempo. Cuando el orden del índice es el mismo que el orden de las columnas en ORDER BY y todas las columnas están en la misma dirección (todas ascendentes o todas descendentes), puede usar el índice para ordenar. Si la consulta es para unir varias tablas, el índice se utilizará solo cuando todas las columnas de ORDER BY sean columnas de la primera tabla. Filesort se utilizará en otros casos.

Cuando MySQL no puede usar el índice para ordenar, usará su propio algoritmo de ordenación (algoritmo de ordenación rápida) para ordenar los datos en la memoria (búfer de ordenación). Si la memoria no se puede cargar, dividirá los datos en el disco en bloques. , y luego Clasifique cada bloque de datos, y luego combine cada bloque en un conjunto de resultados ordenado (de hecho, la clasificación externa). Para el ordenamiento de archivos, MySQL tiene dos algoritmos de ordenamiento.

(1) Algoritmo de escaneo de dos pasos

El método de implementación es sacar primero los campos que necesitan ser ordenados y la información del puntero que se puede ubicar directamente en los datos de la fila relevante, y luego ordenar en la memoria establecida (establecida por el parámetro sort_buffer_size), y después de ordenar es completado, saque la información requerida nuevamente a través de las columnas de información del puntero de fila.

Nota: Este algoritmo es el utilizado antes de 4.1 Necesita acceder a los datos dos veces, especialmente la segunda operación de lectura provocará muchas operaciones de E / S aleatorias. Por otro lado, la sobrecarga de memoria es pequeña.

(2) Un algoritmo de escaneo (paso único)

Este algoritmo saca todas las columnas requeridas a la vez y genera el resultado directamente después de ordenar en la memoria.

Nota: Este algoritmo se ha utilizado desde MySQL 4.1. Reduce el número de E / S y es más eficiente, pero la sobrecarga de memoria también es mayor. Si eliminamos las columnas que no son necesarias, desperdiciará enormemente la memoria necesaria para el proceso de clasificación. En versiones posteriores a MySQL 4.1, puede establecer el parámetro max_length_for_sort_data para controlar si MySQL elige el primer algoritmo de clasificación o el segundo. Cuando el tamaño total de todos los campos grandes extraídos es mayor que la configuración de max_length_for_sort_data, MySQL elegirá usar el primer algoritmo de clasificación, de lo contrario, elegirá el segundo. Para mejorar el rendimiento de clasificación tanto como sea posible, naturalmente preferimos utilizar el segundo algoritmo de clasificación, por lo que es muy necesario extraer solo las columnas necesarias de la consulta.

Al ordenar la operación de unión, si ORDER BY solo se refiere a las columnas de la primera tabla, MySQL realiza una operación de ordenación de archivos en la tabla y luego realiza el procesamiento de unión. En este momento, EXPLAIN genera "Usando ordenación de archivos"; de lo contrario, MySQL debe consultar el El conjunto de resultados genera una tabla temporal, y la operación de ordenamiento de archivos se realiza después de que se completa la conexión. En este momento, EXPLAIN genera "Uso temporal; Uso de ordenamiento de archivos".

3.4, índice y bloqueo

Los índices son muy importantes para InnoDB porque permite que las consultas bloqueen menos tuplas. Esto es muy importante, porque en MySQL 5.0, InnoDB no se desbloqueará hasta que se confirme la transacción. Hay dos razones: Primero, incluso si la sobrecarga del bloqueo de nivel de fila de InnoDB es muy eficiente, la sobrecarga de memoria también es pequeña, pero no importa qué, todavía hay sobrecarga. En segundo lugar, el bloqueo de tuplas innecesarias aumentará la sobrecarga del bloqueo y reducirá la concurrencia.

InnoDB solo bloquea las tuplas a las que se debe acceder, y los índices pueden reducir la cantidad de tuplas a las que accede InnoDB. Sin embargo, este objetivo solo se puede lograr filtrando esos datos no deseados en la capa del motor de almacenamiento. Una vez que el índice no permite a InnoDB hacer eso (es decir, no puede lograr el propósito de filtrado), el servidor MySQL solo puede realizar operaciones WHERE en los datos devueltos por InnoDB. En este momento, es inevitable bloquear esas tuplas: InnoDB ha bloqueado esos elementos Group, el servidor ya no se puede desbloquear.

Veamos un ejemplo:

La consulta solo devuelve 2 --- 3 datos y en realidad tiene bloqueos exclusivos en 1 --- 3 datos. InnoDB bloquea la tupla 1 porque el plan de consulta de MySQL solo usa índices para consultas de rango (sin filtrar, la segunda condición en WHERE ya no puede usar índices):

Indica que el motor de almacenamiento comienza al principio del índice y recupera todas las filas hasta que actor_id <4 sea falso, y el servidor no puede decirle a InnoDB que elimine la tupla 1. Para demostrar que la fila 1 se ha bloqueado, creamos otra conexión y realizamos las siguientes operaciones:

La consulta se suspenderá y no se ejecutará hasta que la primera transacción conectada se comprometa a liberar el bloqueo (este comportamiento es necesario para la replicación basada en instrucciones). Como se muestra arriba, al usar un índice, InnoDB bloqueará las tuplas que no necesite. Peor aún, si la consulta no puede usar el índice, MySQL realizará un escaneo completo de la tabla y bloqueará cada tupla, independientemente de si realmente es necesaria.

Supongo que te gusta

Origin blog.csdn.net/Linuxhus/article/details/112392001
Recomendado
Clasificación