← Назад к вопросам

Как в 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% случаев это решает проблему.

Как в PostgreSQL посмотреть количество записей? | PrepBro