← Назад к вопросам
Как в PostgreSQL посмотреть количество записей?
2.0 Middle🔥 171 комментариев
#Базы данных (NoSQL)#Базы данных (SQL)
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как посчитать записи в PostgreSQL
Просто, но есть важные нюансы производительности и точности.
Метод 1: COUNT(*) — простой и универсальный
SELECT COUNT(*) FROM users;
-- Результат: 1000000 (точное число строк)
Плюсы:
- Простой
- Работает для любой таблицы
- Игнорирует NULL
Минусы:
- Медленно на больших таблицах (> 1М строк)
- Полносканирует таблицу
- Может заблокировать другие запросы
Метод 2: COUNT(id) — считает непустые значения
SELECT COUNT(id) FROM users;
-- Результат: 1000000
SELECT COUNT(deleted_at) FROM users;
-- Результат: 100000 (только те, где deleted_at не NULL)
Разница от COUNT(*):
-- Таблица с NULL значениями
| id | name | deleted_at |
|----|-------------|------------|
| 1 | Alice | NULL |
| 2 | Bob | 2024-01-15 |
| 3 | Charlie | NULL |
SELECT COUNT(*) FROM users; -- 3
SELECT COUNT(deleted_at) FROM users; -- 1 (только Bob)
Метод 3: COUNT(DISTINCT column) — считает уникальные
SELECT COUNT(DISTINCT email) FROM users;
-- Результат: 980000 (если 20k дублей)
-- Посчитать уникальные платежи по пользователям
SELECT COUNT(DISTINCT user_id) FROM payments;
Минус: очень медленно на больших таблицах
Метод 4: Быстрое приблизительное число (для больших таблиц)
-- PostgreSQL хранит примерное число строк в pg_class
SELECT n_live_tup FROM pg_stat_user_tables
WHERE relname = 'users';
-- Результат: 1000000 (может быть неточным)
-- Или с join на информационную схему
SELECT
schemaname,
tablename,
n_live_tup as row_count
FROM pg_stat_user_tables
ORDER BY n_live_tup DESC;
Когда использовать:
- Нужно только приблизительное число
- Таблица огромная (> 100М)
- Скорость критична
Метод 5: С условием WHERE
SELECT COUNT(*) FROM users WHERE status = 'active';
-- Только активные пользователи
SELECT COUNT(*) FROM orders
WHERE created_at > CURRENT_DATE - INTERVAL '30 days';
-- За последние 30 дней
Оптимизация: индекс
-- Создать индекс для быстрого count
CREATE INDEX idx_users_status ON users(status);
-- Теперь COUNT WHERE status = 'active' будет быстрее
Метод 6: Несколько условий одновременно
SELECT
COUNT(*) FILTER (WHERE status = 'active') as active_users,
COUNT(*) FILTER (WHERE status = 'deleted') as deleted_users,
COUNT(*) as total_users
FROM users;
Результат:
active_users | deleted_users | total_users
800000 | 200000 | 1000000
Один проход, все три count'а.
Метод 7: Группировка с COUNT
SELECT
status,
COUNT(*) as count
FROM users
GROUP BY status;
-- Результат:
-- status | count
-- active | 800000
-- deleted | 200000
-- inactive| 0 (если нет записей)
Метод 8: COUNT с HAVING (фильтр после COUNT)
SELECT
department_id,
COUNT(*) as emp_count
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 10; -- Только отделы с > 10 сотрудников
Python: Когда использовать каждый метод
# 1. ORM (Django)
from django.db.models import Count
# Простой count
user_count = User.objects.count()
# С условием
active_count = User.objects.filter(status='active').count()
# С группировкой
from django.db.models import Count
stats = User.objects.values('status').annotate(
count=Count('id')
)
# Результат: [{'status': 'active', 'count': 800000}, ...]
# 2. SQLAlchemy
from sqlalchemy import func
session.query(func.count(User.id)).scalar() # 1000000
# С условием
session.query(func.count(User.id)).filter(
User.status == 'active'
).scalar() # 800000
# 3. Raw SQL
import psycopg2
conn = psycopg2.connect("dbname=mydb")
cur = conn.cursor()
cur.execute("SELECT COUNT(*) FROM users")
count = cur.fetchone()[0]
print(count) # 1000000
Питфоллы
Проблема 1: COUNT медленно на больших таблицах
-- Медленно: полносканирование
SELECT COUNT(*) FROM huge_table; -- 10 секунд
-- Быстро: индекс
CREATE INDEX idx_huge_table_id ON huge_table(id);
SELECT COUNT(id) FROM huge_table; -- 100мс (PostgreSQL может использовать индекс)
Проблема 2: Неточность с параллельными вставками
-- Thread 1
BEGIN;
INSERT INTO users VALUES (...);
-- Thread 2 (одновременно)
SELECT COUNT(*) FROM users;
-- Может вернуть или не вернуть запись из Thread 1
-- Зависит от isolation level (READ COMMITTED vs SERIALIZABLE)
Проблема 3: Забыли про VACUUM
-- После многих DELETE COUNT может быть медленным
-- PostgreSQL не удаляет строки, они остаются как "мертвые"
VACUUM users; -- Очистить
ANALYZE users; -- Обновить статистику
SELECT COUNT(*) FROM users; -- Теперь быстрее
Рекомендации
| Ситуация | Метод | Причина |
|---|---|---|
| Нужно точное число | COUNT(*) | Гарантированно точно |
| Таблица < 1М | COUNT(*) | Быстро |
| Таблица > 100М | pg_stat_user_tables | Фастер |
| С условиями | COUNT(...) WHERE | Используй индекс |
| Много разных count'ов | FILTER | Один проход |
| Группировка | COUNT GROUP BY | Встроенная функция |
Золотое правило: Если COUNT медленный — проверь наличие индекса на WHERE колонке. В 90% случаев это решает проблему.