Я знаю, что воскрешаю довольно старый вопрос, но недавно я столкнулся с этой проблемой, но мне нужно что-то, что хорошо масштабируется до больших чисел . Не было никаких существующих данных о производительности, и, поскольку этому вопросу было уделено довольно много внимания, я решил опубликовать то, что нашел.
Решениями, которые действительно сработали, были двойной подзапрос /NOT IN
метод Алекса Барретта (аналогичный методу Билла Карвина ) и метод КвасснойLEFT JOIN
.
К сожалению, оба вышеперечисленных метода создают очень большие промежуточные временные таблицы, и производительность быстро снижается, поскольку количество записей, которые не удаляются, становится большим.
То, что я выбрал, использует двойной подзапрос Алекса Барретта (спасибо!), Но <=
вместо этого использует 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
)
Он использует OFFSET
для получения идентификатора N- й записи и удаляет эту запись и все предыдущие записи.
Поскольку порядок уже является условием этой проблемы ( ORDER BY id DESC
), <=
он идеально подходит.
Это намного быстрее, поскольку временная таблица, созданная подзапросом, содержит только одну запись вместо N записей.
Прецедент
Я протестировал три метода работы и новый метод, описанный выше, в двух тестовых случаях.
Оба тестовых примера используют 10000 существующих строк, в то время как первый тест сохраняет 9000 (удаляет самую старую 1000), а второй тест сохраняет 50 (удаляет самые старые 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 |
+
Что интересно, этот <=
метод показывает лучшую производительность по всем направлениям, но на самом деле становится лучше, чем больше вы храните, а не хуже.