Sei que estou ressuscitando uma questão bastante antiga, mas recentemente me deparei com esse problema, mas precisava de algo que se dimensionasse bem para grandes números . Não havia nenhum dado de desempenho existente, e como esta questão chamou bastante atenção, pensei em postar o que encontrei.
As soluções que realmente funcionaram foram a subconsulta /NOT IN método duplo de Alex Barrett (semelhante ao de Bill Karwin ) e oLEFT JOIN método de Quassnoi .
Infelizmente, os dois métodos acima criam tabelas temporárias intermediárias muito grandes e o desempenho diminui rapidamente à medida que aumenta o número de registros que não estão sendo excluídos.
O que decidi utiliza a subconsulta dupla de Alex Barrett (obrigado!), Mas usa em <=vez 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
)
Ele usa OFFSETpara obter o ID do N º registro e exclui esse registro e todos os registros anteriores.
Como ordenar já é uma suposição desse problema ( ORDER BY id DESC), <=é um ajuste perfeito.
É muito mais rápido, pois a tabela temporária gerada pela subconsulta contém apenas um registro em vez de N registros.
Caso de teste
Testei os três métodos de trabalho e o novo método acima em dois casos de teste.
Ambos os casos de teste usam 10.000 linhas existentes, enquanto o primeiro teste mantém 9.000 (exclui os 1.000 mais antigos) e o segundo teste mantém 50 (exclui os 9950 mais antigos).
+
| | 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 |
+
O que é interessante é que o <=método tem melhor desempenho em todas as áreas, mas na verdade fica melhor quanto mais você guarda, em vez de piorar.