Sé que estoy resucitando una pregunta bastante antigua, pero recientemente me encontré con este problema, pero necesitaba algo que se adapte bien a grandes números . No había datos de rendimiento existentes, y dado que esta pregunta ha recibido bastante atención, pensé en publicar lo que encontré.
Las soluciones que realmente funcionaron fueron el método / NOT IN
subconsulta doble de Alex Barrett (similar al de Bill Karwin ) y elLEFT JOIN
método de Quassnoi .
Desafortunadamente, los dos métodos anteriores crean tablas temporales intermedias muy grandes y el rendimiento se degrada rápidamente a medida que aumenta la cantidad de registros que no se eliminan.
Lo que me decidí utiliza la doble subconsulta de Alex Barrett (¡gracias!) Pero usa en <=
lugar de NOT IN
:
DELETE FROM `test_sandbox`
WHERE id <= (
SELECT id
FROM (
SELECT id
FROM `test_sandbox`
ORDER BY id DESC
LIMIT 1 OFFSET 42
) foo
)
Se utiliza OFFSET
para obtener la identificación del registro N y elimina ese registro y todos los registros anteriores.
Dado que ordenar ya es una suposición de este problema ( ORDER BY id DESC
), <=
es un ajuste perfecto.
Es mucho más rápido, ya que la tabla temporal generada por la subconsulta contiene solo un registro en lugar de N registros.
Caso de prueba
Probé los tres métodos de trabajo y el nuevo método anterior en dos casos de prueba.
Ambos casos de prueba usan 10000 filas existentes, mientras que la primera prueba conserva 9000 (elimina las 1000 más antiguas) y la segunda prueba 50 (elimina las 9950 más antiguas).
+
| | 10000 TOTAL, KEEP 9000 | 10000 TOTAL, KEEP 50 |
+
| NOT IN | 3.2542 seconds | 0.1629 seconds |
| NOT IN v2 | 4.5863 seconds | 0.1650 seconds |
| <=,OFFSET | 0.0204 seconds | 0.1076 seconds |
+
Lo interesante es que el <=
método ve un mejor rendimiento en todos los ámbitos, pero en realidad mejora cuanto más se conserva, en lugar de peor.