Un análisis de consulta SQL principio de optimización (900W + datos, desde los 17s a 300 ms)

Hay una mesa de flujo financiero, la consulta tarda no sub-biblioteca sub-tabla, la cantidad actual de datos era 9.555.695, las consultas de paginación utiliza para limitar, para optimizar el anterior 16 S 938 MS  (ejecución: 16 S 831 MS, ir a buscar: 107 MS), de acuerdo con después de ajustar el SQL siguiente manera, el consumo de 347 MS  (Ejecución: MS 163, ir a buscar puede: MS 184);

Acción:  consulta en subconsultas, subconsultas sólo el ID de la llave primaria de búsqueda, y luego utilizando la clave primaria de las subconsultas asociados en una consulta para determinar otro campo de atributos;

Principio:  reducir de nuevo a la operación de la mesa;

-- 优化前SQL
SELECT  各种字段
FROM`table_name`
WHERE 各种条件
LIMIT 0,10;
-- 优化后SQL
SELECT  各种字段
FROM `table_name` main_tale
RIGHT JOIN
(
SELECT  子查询只查主键
FROM `table_name`
WHERE 各种条件
LIMIT 0,10;
) temp_table ON temp_table.主键 = main_table.主键

Encontrado análisis de principio: ¿Por qué MySQL con límite afectaría el rendimiento?

I. Introducción

En primer lugar, explicar la versión de MySQL:

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.17    |
+-----------+
1 row in set (0.00 sec)

Estructura de la tabla:

mysql> desc test;
+--------+---------------------+------+-----+---------+----------------+
| Field  | Type                | Null | Key | Default | Extra          |
+--------+---------------------+------+-----+---------+----------------+
| id     | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| val    | int(10) unsigned    | NO   | MUL | 0       |                |
| source | int(10) unsigned    | NO   |     | 0       |                |
+--------+---------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

id para el incremento de clave principal, val índice no único.

grandes cantidades vertidas de datos, un total de 500 millones:

mysql> select count(*) from test;
+----------+
| count(*) |
+----------+
|  5242882 |
+----------+
1 row in set (4.25 sec)

Sabemos que cuando el límite de offset filas de grande, habrá eficiencia:

mysql> select * from test where val=4 limit 300000,5;
+---------+-----+--------+
| id      | val | source |
+---------+-----+--------+
| 3327622 |   4 |      4 |
| 3327632 |   4 |      4 |
| 3327642 |   4 |      4 |
| 3327652 |   4 |      4 |
| 3327662 |   4 |      4 |
+---------+-----+--------+
5 rows in set (15.98 sec)

Con el fin de lograr el mismo objetivo, por lo general, volveremos a escribir la siguiente declaración:

mysql> select * from test a inner join (select id from test where val=4 limit 300000,5) b on a.id=b.id;
+---------+-----+--------+---------+
| id      | val | source | id      |
+---------+-----+--------+---------+
| 3327622 |   4 |      4 | 3327622 |
| 3327632 |   4 |      4 | 3327632 |
| 3327642 |   4 |      4 | 3327642 |
| 3327652 |   4 |      4 | 3327652 |
| 3327662 |   4 |      4 | 3327662 |
+---------+-----+--------+---------+
5 rows in set (0.38 sec)

diferencia de tiempo es obvia.

¿Por qué existe el resultado de lo anterior? Nos fijamos en el selecto * de prueba donde val = 4 límite de 300000,5; el proceso de consulta:

Las consultas a los datos de nodo de hoja de índice. Todas las consultas sobre el valor del campo de índice requerido de acuerdo con la llave maestra para el grupo de nodos hoja.

Esta cifra es similar a la siguiente:

Al igual que anteriormente, necesidad, inode 300,005 veces, los datos de 300,005 tiempos de consulta de índice agrupado, a continuación, el resultado final filtra 300.000 antes, eliminado los últimos cinco. MySQL costar mucho al azar de E / S en el índice agrupado consulta de datos, mientras que los datos 300000 E / S aleatorias a la consulta no aparecerán en el resultado del conjunto de.

Seguro que alguien le preguntará: Desde el inicio de la utilización del índice, por qué no primero de verificación a lo largo del nodo hoja Índice de nodo últimos cinco necesidades, y luego ir índice agrupado para consultar los datos reales. Por lo que sólo el 5 E / S aleatorias, el proceso es similar a la siguiente imagen:

De hecho, quiero hacer esta pregunta.

Confirmar

Aquí nos fijamos en la operación real para confirmar el razonamiento anterior:

Para confirmar el select * from test where val=4 limit 300000,5nodo de datos de exploración en el índice de los nodos 300 y 005 300 005 índice agrupado, tenemos que saber que no hay manera de contar el número de datos de consulta de MySQL a través del nodo de índice en un nodo en SQL. La primera vez que probé Handler_read_ * serie, por desgracia no es una variable para satisfacer las condiciones.

Sólo se puede confirmar a través de una forma indirecta:

Hay INNODB agrupación de almacenamiento intermedio. Que contiene las páginas visitadas recientemente datos, incluyendo datos y páginas de índice. Así que tenemos que ejecutar dos sql, comparar el número de páginas de datos en el grupo de búferes. El resultado se prevé ejecutar select * from test a inner join (select id from test where val=4 limit 300000,5); después de que el número de páginas de datos agrupación de almacenamiento intermedio es mucho menor que select * from test where val=4 limit 300000,5;el número de SQL correspondiente anterior debido a que sólo cinco veces la página de datos de acceso, y luego una página de acceso a datos SQL 300005 veces.

select * from test where val=4 limit 300000,5
mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like'%test%'group by index_name;
Empty set (0.04 sec)

Como puede verse, no hay páginas de datos agrupación de almacenamiento intermedio en la mesa de prueba.

mysql> select * from test where val=4 limit 300000,5;
+---------+-----+--------+
| id      | val | source |
+---------+-----+--------+|
3327622 |   4 |      4 |
| 3327632 |   4 |      4 |
| 3327642 |   4 |      4 |
| 3327652 |   4 |      4 |
| 3327662 |   4 |      4 |
+---------+-----+--------+
5 rows in set (26.19 sec)

mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like'%test%'group by index_name;
+------------+----------+
| index_name | count(*) |
+------------+----------+
| PRIMARY    |     4098 |
| val        |      208 |
+------------+----------+2 rows in set (0.04 sec)

Como puede verse, en este caso de grupo de búfer en la tabla de prueba tiene una página de datos de 4098, página 208 índice.

select * from test a inner join (select id from test where val=4 limit 300000,5) ;Para evitar los efectos de la última prueba, hay que vaciar el grupo de búferes, MySQL reiniciado.

mysqladmin shutdown
/usr/local/bin/mysqld_safe &
mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like'%test%'group by index_name;

Empty set (0.03 sec)

SQL que se ejecutan:

mysql> select * from test a inner join (select id from test where val=4 limit 300000,5) b on a.id=b.id;
+---------+-----+--------+---------+
| id      | val | source | id      |
+---------+-----+--------+---------+
| 3327622 |   4 |      4 | 3327622 |
| 3327632 |   4 |      4 | 3327632 |
| 3327642 |   4 |      4 | 3327642 |
| 3327652 |   4 |      4 | 3327652 |
| 3327662 |   4 |      4 | 3327662 |
+---------+-----+--------+---------+
5 rows in set (0.09 sec)

mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like'%test%'group by index_name;
+------------+----------+
| index_name | count(*) |
+------------+----------+
| PRIMARY    |        5 |
| val        |      390 |
+------------+----------+
2 rows in set (0.03 sec)

Podemos ver claramente ver la diferencia entre los dos: el primero sql cargado con 4098 páginas de datos a la memoria, mientras que el segundo SQL sólo cinco páginas de datos cargados en el grupo de búferes. En línea con nuestro pronóstico. También confirmó por qué la primera SQL será lenta: leer grandes cantidades de líneas de datos inútiles (300.000), pero finalmente se descartó. Y va a causar un problema: una gran cantidad de puntos calientes no es muy alta carga de datos en el grupo de búferes página, puede causar la contaminación del grupo de búfer, la huella de la agrupación de almacenamiento intermedio. problemas encontrados

Para vaciar la agrupación de almacenamiento intermedio para garantizar que en cada reinicio, necesitamos cerca innodb_buffer_pool_dump_at_shutdown y innodb_buffer_pool_load_at_startup, estas dos opciones pueden controlar el volcado de la base de datos a cabo el grupo de búferes de datos se cierra y cargar datos de grupo de búfer de copia de seguridad en el disco, mientras que la base de datos está abierta.

material de referencia

1.https: //explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/

2.https: //dev.mysql.com/doc/refman/5.7/en/innodb-information-schema-buffer-pool-tables.html

Publicado 50 artículos originales · ganado elogios 1706 · Vistas 2,22 millones +

Supongo que te gusta

Origin blog.csdn.net/zl1zl2zl3/article/details/105325510
Recomendado
Clasificación