Я знаю, що я відроджую досить давнє запитання, але нещодавно я зіткнувся з цим питанням, але мені потрібно було щось, що добре масштабується . Не було жодних існуючих даних про ефективність, і оскільки цьому питанню було приділено досить багато уваги, я думав опублікувати те, що знайшов.
Рішеннями, які насправді спрацювали, були подвійний 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 |
+
Цікаво те, що <=
метод бачить кращу продуктивність у цілому, але насправді стає кращим, чим більше ви тримаєте, а не гірше.