So che sto resuscitando una vecchia domanda, ma recentemente mi sono imbattuto in questo problema, ma avevo bisogno di qualcosa che si adattasse bene a grandi numeri . Non c'erano dati sulle prestazioni esistenti e, poiché questa domanda ha ricevuto un po 'di attenzione, ho pensato di pubblicare ciò che ho trovato.
Le soluzioni che hanno effettivamente funzionato erano la doppia NOT IN
sottoquery / metodo di Alex Barrett (simile a quello di Bill Karwin ) e ilLEFT JOIN
metodo di Quassnoi .
Sfortunatamente, entrambi i metodi precedenti creano tabelle temporanee intermedie molto grandi e le prestazioni diminuiscono rapidamente man mano che il numero di record non eliminati aumenta.
Quello che ho scelto utilizza la doppia sottoquery di Alex Barrett (grazie!) Ma usa <=
invece di 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
)
Viene utilizzato OFFSET
per ottenere l'ID dell'N- esimo record ed elimina quel record e tutti i record precedenti.
Poiché l'ordinazione è già un presupposto di questo problema ( ORDER BY id DESC
), <=
è perfetto.
È molto più veloce, poiché la tabella temporanea generata dalla sottoquery contiene solo un record invece di N record.
Scenario di prova
Ho testato i tre metodi di lavoro e il nuovo metodo sopra in due casi di test.
Entrambi i casi di test utilizzano 10000 righe esistenti, mentre il primo test ne mantiene 9000 (elimina le 1000 meno recenti) e il secondo ne mantiene 50 (elimina le 9950 meno recenti).
+
| | 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 |
+
La cosa interessante è che il <=
metodo vede prestazioni migliori su tutta la linea, ma in realtà migliora più mantieni, anziché peggio.