MySQL desplaza filas infinitas


114

Me gustaría construir una consulta que muestre todos los resultados en una tabla, pero que esté compensada por 5 desde el inicio de la tabla. Por lo que puedo decir, MySQL LIMITrequiere un límite y una compensación. ¿Hay alguna forma de hacer esto?


1
Esta es una pregunta totalmente válida, pero me pregunto si lo que sería mejor es tomar todo y descartar los primeros registros mediante programación. Dado el horror de lo que parece ser la mejor respuesta (límite 5, 18446744073709551615), preferiría trabajar alrededor de las limitaciones del LIMIT de MySQL.
cesoide

3
@cesoid que si quieres limit 5000, 18446744073709551615. No va a obtener 5000 filas adicionales solo para que su código se vea bonito.
elipoultorak

@ user3576887 Creo que tiene razón, solo estaba considerando la pregunta anterior con la suposición de que 5 era el único requisito, en lugar de una cantidad variable que podría ser mucho mayor (y en lugar de resolver el problema de otra persona).
cesoide

Sugiero que esta es una tarea tan rara que se puede aceptar la fealdad de la solución.
Rick James

Respuestas:


151

Del manual de MySQL en LIMIT :

Para recuperar todas las filas desde un cierto desplazamiento hasta el final del conjunto de resultados, puede usar un número grande para el segundo parámetro. Esta declaración recupera todas las filas desde la fila 96 hasta la última:

SELECT * FROM tbl LIMIT 95, 18446744073709551615;

105
¡Horrible! Vine aquí con la esperanza de que MySQL hiciera que la cláusula de límite fuera opcional, como está, pero también con un desplazamiento proporcionado ... ¡pero no! He visto este 18446744073709551615 dispersarse por todo el código y estaba culpando a los programadores perezosos, ¡pero es una característica de diseño!
Petruza

8
horrible respuesta, pero eso es oficial de MySQL Doc. Lo que puedo decir @ _ @
GusDeCooL

21
18446744073709551615 es 2 ^ 64-1 para aquellos que se preguntaban. Es posible que desee tener cuidado porque no podrá almacenar este valor en un entero de 32 bits. Debe asegurarse de almacenar esto como una cadena para garantizar la compatibilidad.
AlicanC

13
¡Terrible! necesitan ser más elegantes que eso ... ¡ Limit -1o se Limit Nullven bastante razonables! o al menos Limit debería aceptar una subconsulta comoselect * from table limit (select count(*) from table)
vulcan raven

19
use php 'PHP_INT_MAX' para evitar efectos de desbordamiento.
Karl Adler

24

Como mencionaste, se requiere LIMIT, por lo que debes usar el límite más grande posible, que es 18446744073709551615 (máximo de BIGINT sin firmar)

SELECT * FROM somewhere LIMIT 18446744073709551610 OFFSET 5

33
Vaya, ¿es esta la solución oficial del equipo de MySQL?
Antony

12

Como se señaló en otras respuestas, MySQL sugiere usar 18446744073709551615 como el número de registros en el límite, pero considere esto: ¿Qué haría si recuperara 18,446,744,073,709,551,615 registros? De hecho, ¿qué harías si obtuvieras 1,000,000,000 de registros?

Tal vez desee más de mil millones de registros, pero mi punto es que hay un límite en el número que desea , y es menos de 18 quintillones. En aras de la estabilidad, la optimización y posiblemente la usabilidad, sugeriría poner un límite significativo a la consulta. Esto también reduciría la confusión para cualquiera que nunca haya visto ese número de aspecto mágico y tendría el beneficio adicional de comunicar al menos cuántos registros está dispuesto a manejar a la vez.

Si realmente debe obtener los 18 trillones de registros de su base de datos, tal vez lo que realmente desee es capturarlos en incrementos de 100 millones y repetir 184 mil millones de veces.


Tiene razón, pero dejar esta decisión en manos del desarrollador no es una buena opción
amd

@amd ¿Podrías explicar eso un poco más? No sé lo que intentas decir.
cesoide

1
@cesoid Creo que está diciendo que los desarrolladores no deberían ser los que elijan arbitrariamente la lógica de negocios, con lo que estoy de acuerdo, pero solo hasta cierto punto. Supongamos que está devolviendo una lista de pedidos a un cliente. Es perfectamente razonable no devolver nunca más de, digamos, un millón a la vez, pero limitarlo a 100 podría causar confusión.
Otoño Leonard

@amd No estoy diciendo que el desarrollador deba cambiar el comportamiento de la aplicación para evitar usar 18446744073709551615. Estoy diciendo que deben considerar si usar ese número tiene sentido como parte de la implementación de cualquier cliente o diseñador de interfaz. ha solicitado, y que es muy poco probable que sea la implementación correcta para nada. La decisión de usar MySQL probablemente ya la tomó el desarrollador sin preguntar si habría más de 18 trillones de algo.
cesoide

5

Otro enfoque sería seleccionar una columna autoimcrementada y luego filtrarla usando HAVING.

SET @a := 0; 
select @a:=@a + 1 AS counter, table.* FROM table 
HAVING counter > 4

Pero probablemente me quedaría con el enfoque de límite alto.


gracias, y me pregunto cómo puedo poner esa consulta en una declaración PHP. $sql = 'SET @a :=0 SELECT .....';
Quiero

2

Como otros mencionaron, del manual de MySQL. Para lograr eso, puede usar el valor máximo de un gran int sin firmar, que es este número terrible (18446744073709551615). Pero para hacerlo un poco menos complicado, puede utilizar el operador bit a bit tilde "~".

  LIMIT 95, ~0

funciona como una negación bit a bit. El resultado de "~ 0" es 18446744073709551615.


1
No funciona en MariaDB 10.3 :( LIMIT 5, ~0LIMIT ~0 OFFSET 5
Probé

1
Esto no es una cosa en MySQL 5.7 - sintaxis inválida.
Jonny Nott

0

Justo hoy estaba leyendo sobre la mejor manera de obtener grandes cantidades de datos (más de un millón de filas) de una tabla mysql. Una forma es, como se sugiere, usar LIMIT x,ydónde xestá el desplazamiento y yla última fila que desea devolver. Sin embargo, como descubrí, no es la forma más eficiente de hacerlo. Si tiene una columna de autoincremento, puede usar fácilmente una SELECTdeclaración con una WHEREcláusula que diga desde qué registro le gustaría comenzar.

Por ejemplo, SELECT * FROM table_name WHERE id > x;

Parece que mysql obtiene todos los resultados cuando lo usa LIMITy luego solo le muestra los registros que encajan en el desplazamiento: no es el mejor para el rendimiento.

Fuente: Respuesta a esta pregunta Foros de MySQL . Solo tome nota, la pregunta tiene aproximadamente 6 años.


13
Esto dará resultados incorrectos si alguna vez borró un registro. Este método es especialmente peligroso, porque funciona la mayor parte del tiempo y falla silenciosamente cuando no lo hace.
2014

0

Puede usar una declaración de MySQL con LIMIT:

START TRANSACTION;
SET @my_offset = 5;
SET @rows = (SELECT COUNT(*) FROM my_table);
PREPARE statement FROM 'SELECT * FROM my_table LIMIT ? OFFSET ?';
EXECUTE statement USING @rows, @my_offset;
COMMIT;

Probado en MySQL 5.5.44. Así, podemos evitar la inserción del número 18446744073709551615.

nota: la transacción asegura que la variable @rows esté de acuerdo con la tabla considerada en la ejecución de la sentencia.


como dijo @amd: "seleccionar recuento (*) en una tabla con 7
millones de

-1

Sé que esto es antiguo, pero no vi una respuesta similar, así que esta es la solución que usaría.

Primero, ejecutaría una consulta de recuento en la tabla para ver cuántos registros existen. Esta consulta es rápida y normalmente el tiempo de ejecución es insignificante. Algo como:

SELECT COUNT(*) FROM table_name;

Luego, construiría mi consulta usando el resultado que obtuve del recuento como mi límite (ya que ese es el número máximo de filas que la tabla podría devolver). Algo como:

SELECT * FROM table_name LIMIT count_result OFFSET desired_offset;

O posiblemente algo como:

SELECT * FROM table_name LIMIT desired_offset, count_result;

Por supuesto, si es necesario, puede restar deseado_desplazamiento de count_result para obtener un valor real y exacto para suministrar como límite. Pasar el valor "18446744073709551610" simplemente no tiene sentido si realmente puedo determinar un límite apropiado para proporcionar.


2
seleccionar recuento (*) en una tabla con 7 millones de registros toma alrededor de 17
segundos

-7
WHERE .... AND id > <YOUROFFSET>

id puede ser cualquier columna numérica única o autoincrementada que tenga ...


7
Mala idea. Dará el desplazamiento incorrecto si alguna vez ha eliminado una fila.
2014
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.