En resumen: una tabla con más de 16 millones de registros [2 GB de tamaño]. Cuanto mayor es el desplazamiento de LIMIT con SELECT, más lenta se vuelve la consulta, cuando se usa ORDER BY * primary_key *
Entonces
SELECT * FROM large ORDER BY `id` LIMIT 0, 30
toma mucho menos de
SELECT * FROM large ORDER BY `id` LIMIT 10000, 30
Eso solo ordena 30 registros y lo mismo de todos modos. Entonces no es la sobrecarga de ORDER BY.
Ahora, al buscar las últimas 30 filas, toma alrededor de 180 segundos. ¿Cómo puedo optimizar esa simple consulta?
mysql
performance
sql-order-by
limit
Rahman
fuente
fuente
Respuestas:
Es normal que las compensaciones más altas ralenticen la consulta, ya que la consulta necesita contar los primeros
OFFSET + LIMIT
registros (y tomar soloLIMIT
de ellos). Cuanto mayor sea este valor, más tiempo se ejecutará la consulta.La consulta no puede ir directamente a
OFFSET
, porque, en primer lugar, los registros pueden tener una longitud diferente y, en segundo lugar, puede haber huecos en los registros eliminados. Necesita verificar y contar cada registro en su camino.Suponiendo que se
id
trataPRIMARY KEY
de unaMyISAM
tabla, puede acelerarla utilizando este truco:Ver este artículo:
fuente
ORDER BY
o el índice cubre todos los campos que necesita, no necesita esta solución.postgresql
. Esta es una respuesta específica de MySQL.Yo tuve exactamente el mismo problema. Dado el hecho de que desea recopilar una gran cantidad de estos datos y no un conjunto específico de 30, probablemente ejecutará un bucle e incrementará el desplazamiento en 30.
Entonces, lo que puedes hacer es:
WHERE id > lastId limit 0,30
Por lo tanto, siempre puede tener un desplazamiento CERO. Te sorprenderá la mejora del rendimiento.
fuente
MySQL no puede ir directamente al registro número 10000 (o al byte 80000 como sugiere) porque no puede asumir que está empaquetado / ordenado de esa manera (o que tiene valores continuos de 1 a 10000). Aunque podría ser así en la actualidad, MySQL no puede asumir que no hay agujeros / huecos / identificadores eliminados.
Entonces, como se señaló en bobs, MySQL tendrá que buscar 10000 filas (o atravesar la entrada número 10000 del índice
id
) antes de encontrar las 30 para regresar.EDITAR : para ilustrar mi punto
Tenga en cuenta que aunque
sería lento (er) ,
sería rápido (er) y devolvería los mismos resultados siempre que no falten
id
s (es decir, huecos).fuente
Encontré un ejemplo interesante para optimizar las consultas SELECT ORDER BY id LIMIT X, Y. Tengo 35 millones de filas, por lo que me tomó como 2 minutos encontrar un rango de filas.
Aquí está el truco:
Simplemente ponga el DONDE con la última identificación que obtuvo para aumentar mucho el rendimiento. Para mí fue de 2 minutos a 1 segundo :)
Otros trucos interesantes aquí: http://www.iheavy.com/2013/06/19/3-ways-to-optimize-for-paging-in-mysql/
Funciona también con cuerdas.
fuente
La parte que lleva mucho tiempo de las dos consultas es recuperar las filas de la tabla. Lógicamente hablando, en la
LIMIT 0, 30
versión, solo se necesitan recuperar 30 filas. En laLIMIT 10000, 30
versión, se evalúan 10000 filas y se devuelven 30 filas. Puede haber alguna optimización en el proceso de lectura de datos, pero considere lo siguiente:¿Qué pasaría si tuviera una cláusula WHERE en las consultas? El motor debe devolver todas las filas que califican, y luego ordenar los datos, y finalmente obtener las 30 filas.
Considere también el caso en el que las filas no se procesan en la secuencia ORDER BY. Todas las filas que califican deben clasificarse para determinar qué filas devolver.
fuente
Para aquellos que estén interesados en una comparación y cifras :)
Experimento 1: el conjunto de datos contiene aproximadamente 100 millones de filas. Cada fila contiene varios BIGINT, TINYINT, así como dos campos TEXT (deliberadamente) que contienen aproximadamente 1k caracteres.
SELECT * FROM post ORDER BY id LIMIT {offset}, 5
SELECT t.* FROM (SELECT id FROM post ORDER BY id LIMIT {offset}, 5) AS q JOIN post t ON t.id = q.id
... WHERE id>xxx LIMIT 0,5
no aparece aquí, ya que debería ser un tiempo constante.Experimento 2: algo similar, excepto que una fila solo tiene 3 BIGINT.
fuente