Je sais que je ressuscite une question assez ancienne, mais j'ai récemment rencontré ce problème, mais j'avais besoin de quelque chose qui s'adapte bien à de grands nombres . Il n'y avait pas de données de performance existantes, et comme cette question a suscité beaucoup d'attention, j'ai pensé publier ce que j'ai trouvé.
Les solutions qui ont réellement fonctionné étaient la double sous-requête /NOT IN
méthode d' Alex Barrett (similaire à celle de Bill Karwin ) et laLEFT JOIN
méthode de Quassnoi .
Malheureusement, les deux méthodes ci-dessus créent de très grandes tables temporaires intermédiaires et les performances se dégradent rapidement à mesure que le nombre d'enregistrements non supprimés augmente.
Ce sur quoi j'ai choisi utilise la double sous-requête d'Alex Barrett (merci!) Mais utilise à la <=
place 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
)
Il utilise OFFSET
pour obtenir l'ID du N ème enregistrement et supprime cet enregistrement et tous les enregistrements précédents.
Puisque la commande est déjà une hypothèse de ce problème ( ORDER BY id DESC
), <=
est un ajustement parfait.
C'est beaucoup plus rapide, car la table temporaire générée par la sous-requête ne contient qu'un seul enregistrement au lieu de N enregistrements.
Cas de test
J'ai testé les trois méthodes de travail et la nouvelle méthode ci-dessus dans deux cas de test.
Les deux cas de test utilisent 10000 lignes existantes, tandis que le premier test en conserve 9000 (supprime les 1000 plus anciens) et le deuxième test en conserve 50 (supprime les 9950 les plus anciens).
+
| | 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 |
+
Ce qui est intéressant, c'est que la <=
méthode voit de meilleures performances dans tous les domaines, mais s'améliore à mesure que vous en conservez, au lieu de pire.