2010-08-24 8 views
6

Se muestra una tabla con aproximadamente 70K registros en un sitio, que muestra 50 registros por página. La paginación se realiza con limit offset,50 en la consulta, y los registros se pueden pedir en columnas diferentes.Seleccionar es mucho más lento al seleccionar los registros más recientes

Navegación por las últimas páginas (por lo que el desplazamiento es de alrededor de 60.000) hace que las consultas mucho más lento que cuando se navega por las primeras páginas (aproximadamente 10 veces)

Es ésta una cuestión de usar el comando limit? ¿Hay otras formas de obtener los mismos resultados?

+0

Buena pregunta, yo soy no está familiarizado con el funcionamiento de MySQL en este sentido. – RedFilter

+0

Gracias por las respuestas, lo probaremos más tarde con la esperanza de ganar algo de velocidad. – Omiod

Respuesta

7

Con compensaciones grandes, MySQL necesita buscar más registros.

Incluso si el plan utiliza filesort (lo que significa que todos los registros se deberían explorar), MySQL lo optimiza para que sólo $offset + $limit registros superiores están ordenados, lo que hace que sea mucho más eficiente para los valores más bajos de $offset.

La solución típica es indexar las columnas que está ordenando en, grabar el último valor de las columnas y reutilizarla en las consultas posteriores, así:

SELECT * 
FROM mytable 
ORDER BY 
     value, id 
LIMIT 0, 10 

que emite:

value id 

1  234 
3  57 
4  186 
5  457 
6  367 
8  681 
10  366 
13  26 
15  765 
17  345 -- this is the last one 

para acceder a la página siguiente, se debería utilizar:

SELECT * 
FROM mytable 
WHERE (value, id) > (17, 345) 
ORDER BY 
     value, id 
LIMIT 0, 10 

, que utiliza el en dex en (value, id).

Por supuesto, esto no ayudará con las páginas de acceso arbitrario, pero ayuda con la exploración secuencial.

Además, MySQL tiene ciertos problemas con la búsqueda tardía de filas. Si se indexan las columnas, puede valer la pena tratar de reescribir su consulta como esta:

SELECT * 
FROM (
     SELECT id 
     FROM mytable 
     ORDER BY 
       value, id 
     LIMIT $offset, $limit 
     ) q 
JOIN mytable m 
ON  m.id = q.id 

Consulte este artículo para obtener una explicación más detallada:

+0

MySQL soporta esa sintaxis estilo tupla ('(val1, val2)> (1, 2)')? Nunca había visto eso antes. ¿Qué es el combinador (Y, supongo)? Supongo que aprendes algo nuevo todos los días ... – ircmaxell

+0

@ircmaxell: sí lo hace. Es orden lexicográfico, lo mismo que 'val1> 1 OR (val1 = 1 AND val2> 2)' – Quassnoi

+0

Buena respuesta. Aquí hay una presentación que creo que tiene una buena información que está en la misma línea: http://www.slideshare.net/Eweaver/efficient-pagination-using-mysql – nathan

2

Así es como MySQL trata los límites. Si puede ordenar en un índice (y la consulta es lo suficientemente simple) puede dejar de buscar después de encontrar las primeras filas offset + limit. Por lo tanto, LIMIT 0,10 significa que si la consulta es lo suficientemente simple, es posible que solo necesite escanear 10 filas. Pero LIMIT 1000,10 significa que como mínimo necesita escanear 1010 filas. Por supuesto, el número real de filas que deben escanearse depende de una serie de otros factores. Pero el punto aquí es que cuanto menor sea el limit + offset, más bajo que el límite inferior en el número de filas que deben escanearse es ...

En cuanto a las soluciones, optimizaría sus consultas para que la consulta misma sin la cláusula LIMIT es lo más eficiente posible. EXPLAIN es su amigo en este caso ...

Cuestiones relacionadas