У PostgreSQL немає збереженого лічильника рядків таблиці. Через MVCC різні транзакції одночасно бачать різну кількість рядків, тож SELECT count(*) FROM orders мусить переглянути рядки (або індекс) і перевірити видимість кожного. На сотнях мільйонів рядків це секунди чи хвилини.
Що можна зробити:
1. Приблизна кількість зі статистики - миттєво:
SELECT reltuples::bigint AS estimate
FROM pg_class
WHERE oid = 'public.orders'::regclass;
Значення оновлює ANALYZE/autovacuum. Для лічильника «близько 2,4 млн записів» на сторінці адмінки - цілком достатньо.
2. Оцінка для запиту з умовою - з плану:
EXPLAIN SELECT * FROM orders WHERE status = 'paid';
-- rows=183000 у плані - оцінка планувальника
3. Точна кількість швидше: index-only scan по невеликому індексу, якщо visibility map свіжа (після вакууму), - помітно швидше за читання всієї таблиці.
4. Лічильник, що ведеться окремо: таблиця-лічильник, оновлювана тригером чи застосунком, або кеш на кілька хвилин. Точно й миттєво, але з ціною на кожен запис (і точкою конкуренції, якщо всі пишуть в один рядок лічильника).
Практичні висновки:
- Пагінація з «сторінка 1 з 48 213» - дорога на великих таблицях: кожна сторінка - ще й
count(*). LaravelsimplePaginate()чиcursorPaginate()обходяться без підрахунку. - «Чи є хоч один рядок» - не
count(*) > 0, аEXISTS (SELECT 1 ... ): зупиняється на першому знайденому. count(column)не швидший заcount(*)- він ще й перевіряєNULL.