Un análisis del principio de optimización de índices SQL en línea y errores de selección de índices

Se produjo un extraño problema en la consulta del módulo de pedidos del que era responsable mi colega hace dos días. Cuando se agregan las condiciones de filtro, se producirá el problema del tiempo de espera de la consulta. No hay problema al consultar todos los pedidos. El SQL es el siguiente (los datos se han desensibilizado y se usa MySql):

SELECT
	a.consumer_code AS orderCode,
	a.rent_equipment_snid AS eqSn,
	a.powerbank_snid AS pbSn,
	a.rent_merchant_name AS rentMerchant,
	a.rent_merchant_address AS merchantAddress,
	a.rent_date AS rentTime,
	a.close_date AS returnTime,
	a.payment_money AS orderAmount,
	a.order_status AS orderStatus,
	a.consume_schema AS consumeSchema,
	a.transaction_status AS transStatus,
	a.rent_equipment_model AS eqModel 
FROM
	cp_consumer_order_2020_10 a 
WHERE
	a.agent_code = xxxx
	# 下面两个条件就是筛选时才会加上
	AND a.order_status = xxx 
	AND a.close_date IS NULL 
ORDER BY
	a.consumer_code desc

cp_consumer_order_2020_10 es una tabla de pedidos mensuales, con casi 10 millones de datos, consumer_code es la clave principal y agent_code tiene un índice normal.
Ejecuté el SQL anterior en la base de datos y descubrí que el índice agent_code había desaparecido y la eficiencia de la consulta era normal. Luego eliminé las condiciones del filtro y los resultados de la ejecución fueron los mismos.Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí

Lo anterior es un plan de ejecución condicional e incondicional, puedes ver que no hay diferencia. En este momento, me pregunto si hay alguna operación que consuma mucho tiempo en
Inserte la descripción de la imagen aquí
el código : este código no parece tener ninguna operación que consuma mucho tiempo, getAgentOrderList es ejecutar ese SQL, getAgentStaffOrderList también trató de consultar muy rápidamente, debido a la paginación, lo siguiente para La ejecución del ciclo no será particularmente lenta.
¿Es posible que haya ocurrido otro "incidente espiritual"? En este momento, de repente pensé si podría ser causado por la paginación. Todos sabemos que el límite causará consultas lentas cuando el desplazamiento es muy grande, pero aún no hemos pasado la página, que es la primera página, por lo que este no es el problema.
Además, pensé que había visto el problema de los errores de selección de índice al usar limit y order by antes. Así que traje el límite 0,30 y ejecuté el SQL justo ahora en la base de datos. Como era de esperar, apareció SQL lento. En este momento, miro el plan de ejecución de la siguiente manera:
Inserte la descripción de la imagen aquí
Puede ver que Mysql usa el índice de clave principal en este momento, es decir, el campo que ordenamos, por lo que sugiero a mis colegas que usen el índice forzado para forzar el índice normal, y la consulta volverá a la normalidad.
En este punto, la optimización de SQL ha terminado, pero ¿por qué agregar un límite hará que Mysql seleccione el índice incorrecto, y por qué es tan lento usar el índice de clave principal y el número estimado de filas escaneadas es obviamente menor? De acuerdo con el principio de "saber lo que está pasando, pero también saber por qué" verifiqué mucha información, pero no pude resolver por completo las dudas en mi corazón. Al final, lo intenté repetidamente y finalmente lo resolví.

  • En primer lugar, ¿por qué es más rápido tomar un índice normal, pero el índice de clave principal es más lento?
    Debido a que mi SQL es el resultado de consultar el índice de clave principal en orden inverso, el índice está naturalmente ordenado y no necesita ser ordenado, por lo que veo que el campo Extra en el plan de ejecución no tiene el orden de archivos Using, que es más rápido que el índice ordinario, pero este SQL se filtra según las condiciones donde Sí, después de obtener los resultados ordenados, debe eliminar el agent_code y las condiciones una por una para que coincidan. Al ver esto, creo que los lectores deberían entender básicamente. Si no hay límite, entonces este SQL tendrá un escaneo completo de la tabla; y hay un límite de 0,30, ocurrirá la siguiente situación: Primero, los 30 registros que coinciden con la condición where son los correctos Si son los primeros 30 elementos después de la clasificación, entonces mysql solo necesita escanear 30 elementos; si hay menos de 30 elementos o si hay registros coincidentes al final de la clasificación, se escaneará toda la tabla. Sin embargo, el índice normal agent_code no tiene este problema, porque la condición del filtro es agent_code, que se puede hacer coincidir rápidamente.
  • ¿Por qué se usa el índice de clave principal cuando se agrega un límite?
    Porque si el índice de clave principal se usa sin límite, coincidirá con la condición where uno por uno como se mencionó anteriormente, pero no hay límite para el número de elementos devueltos, y se realizará un escaneo completo de la tabla (puede usar el índice forzado (primario) + explicar para ver la fila Es el número total de filas en la tabla (1000w), Mysql cree que es más rápido usar índices ordinarios, porque el número estimado de filas de escaneo para índices ordinarios es menos de 1.8W; pero después de agregar el límite, el número estimado de filas de escaneo para el índice de clave principal puede ser Es menor que el número estimado de líneas de exploración para índices normales, lo que conduce a errores de selección de índice.

Supongo que te gusta

Origin blog.csdn.net/l6108003/article/details/109382533
Recomendado
Clasificación