Wiem, że wskrzeszam dość stare pytanie, ale ostatnio napotkałem ten problem, ale potrzebowałem czegoś, co dobrze skaluje się do dużej liczby . Nie było żadnych istniejących danych dotyczących wydajności, a ponieważ to pytanie przyciągnęło sporo uwagi, pomyślałem, że opublikuję to, co znalazłem.
Rozwiązaniami, które faktycznie zadziałały, były podwójne pod-zapytanie /NOT IN
metoda Alexa Barretta (podobne do Billa Karwina ) i metoda QuassnoiLEFT JOIN
.
Niestety obie powyższe metody tworzą bardzo duże pośrednie tabele tymczasowe, a wydajność szybko spada, ponieważ liczba rekordów, które nie są usuwane, staje się duża.
To, na czym się zdecydowałem, wykorzystuje podwójne zapytanie podrzędne Alexa Barretta (dzięki!), Ale <=
zamiast 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
)
Używa OFFSET
do uzyskania identyfikatora N- tego rekordu i usuwa ten rekord oraz wszystkie poprzednie rekordy.
Ponieważ zamawianie jest już założeniem tego problemu ( ORDER BY id DESC
), <=
jest to idealne dopasowanie.
Jest to znacznie szybsze, ponieważ tymczasowa tabela wygenerowana przez podzapytanie zawiera tylko jeden rekord zamiast N rekordów.
Przypadek testowy
Przetestowałem trzy metody pracy i nową metodę powyżej w dwóch przypadkach testowych.
Oba przypadki testowe używają 10000 istniejących wierszy, podczas gdy pierwszy test zachowuje 9000 (usuwa najstarszy 1000), a drugi test zachowuje 50 (usuwa najstarszy 9950).
+
| | 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 |
+
Co ciekawe, <=
metoda zapewnia lepszą wydajność we wszystkich obszarach, ale w rzeczywistości staje się lepsza, im więcej trzymasz, zamiast gorzej.