Таблиця в SQL - це множина рядків без визначеного порядку. Якщо в запиті немає ORDER BY, база повертає рядки в тому порядку, в якому їй зручно: за індексом, яким скористалася, за фізичним розташуванням, за порядком паралельного виконання.
SELECT * FROM products LIMIT 10;
Сьогодні це «перші 10 вставлених», а завтра - після оновлення MySQL, нового індексу, OPTIMIZE TABLE чи іншого плану запиту - інші 10. Код, що на це покладався, ламається без жодних змін.
Ще підступніше - пагінація з неповним ORDER BY:
SELECT * FROM products ORDER BY created_at DESC LIMIT 20 OFFSET 20;
Якщо багато товарів мають однаковий created_at (масовий імпорт), порядок серед них не визначений. Одні товари з'являтимуться на двох сторінках, інші - на жодній.
Правило: ORDER BY має задавати однозначний порядок - додайте унікальну колонку останньою:
SELECT * FROM products ORDER BY created_at DESC, id DESC LIMIT 20 OFFSET 20;
Коли порядок справді не важливий: «будь-які 10 записів для перевірки», EXISTS, вибірка для обробки порціями, де кожен рядок однаково підходить.
Швидкодія LIMIT з ORDER BY: якщо є індекс, що віддає рядки в потрібному порядку, MySQL читає лише перші N і зупиняється. Без індексу - сортує всі рядки (Using filesort у EXPLAIN), хоча й оптимізує сортування для невеликого LIMIT.
OFFSET на далеких сторінках все одно читає й відкидає всі попередні рядки. Для глибокої пагінації - keyset: WHERE (created_at, id) < (?, ?) ORDER BY created_at DESC, id DESC LIMIT 20.