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

Что делает оператор VACUUM?

1.7 Middle🔥 101 комментариев
#Python Core#Soft Skills#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Оператор VACUUM в PostgreSQL

VACUUM — это критическая операция технического обслуживания базы данных в PostgreSQL. Она удаляет "мёртвые" версии строк и освобождает дисковое пространство. Это очень важно понимать для продакшена.

Проблема: MVCC и мёртвые версии строк

PostgreSQL использует MVCC (Multi-Version Concurrency Control) — каждая транзакция видит снимок данных на момент запуска.

# Пример:
# Было:
UPDATE users SET name = 'Alice' WHERE id = 1;

# В памяти БД:
# Версия 1: id=1, name='John', xmax=null        ← старая версия (мёртвая)
# Версия 2: id=1, name='Alice', xmax=null       ← новая версия (живая)

# DELETE users WHERE id = 1;

# Версия 2: id=1, name='Alice', xmax=123        ← теперь мёртвая (удалена для транзакции 123)

# Проблема: обе версии занимают место на диске!

Что делает VACUUM

# Основная функция:
# 1. Удаляет строки, невидимые для всех активных транзакций
# 2. Освобождает дисковое пространство
# 3. Обновляет индексы
# 4. Обновляет статистику таблицы

# Синтаксис
VACUUM;                          # Вакуум всей БД
VACUUM table_name;               # Вакуум конкретной таблицы
VACUUM VERBOSE table_name;       # С подробным выводом
VACUUM ANALYZE table_name;       # + обновление статистики
VACUUM FULL table_name;          # Полный вакуум (медленный, блокирует)

Пример: когда VACUUM необходимо

-- Было
SELECT * FROM users;  -- Возвращает 1000000 строк
-- disk_usage: 100MB

-- Удалили половину
DELETE FROM users WHERE id % 2 = 0;  -- Удалили 500000 строк
-- disk_usage: ВСЕ ЕЩЕ 100MB! ❌

-- Запустили VACUUM
VACUUM ANALYZE users;
-- disk_usage: ~50MB ✅

-- Теперь дисковое пространство освобождено

VACUUM автоматический (autovacuum)

PostgreSQL может сам запускать VACUUM:

-- Проверить настройки autovacuum
SHOW autovacuum;
-- Результат: on (по умолчанию включен)

SHOW autovacuum_naptime;  
-- Результат: 1min (проверяет каждую минуту)

SHOW autovacuum_vacuum_threshold;
-- Результат: 50 (запускает VACUUM если изменилось 50+ строк)

Различие: VACUUM vs VACUUM FULL

# VACUUM (обычный) — удаляет мёртвые версии
VACUUM table_name;
# + Быстро (можно читать таблицу одновременно)
# - Может не вернуть дисковое пространство ОС
# - Оставляет "дыры" в таблице

# VACUUM FULL — полная переписывание таблицы
VACUUM FULL table_name;
# + Полностью освобождает дисковое пространство
# + Дефрагментирует таблицу
# - МЕДЛЕННО (экслюзивная блокировка)
# - Таблица недоступна для чтения/записи
# - Требует почти в 2 раза больше дискового пространства во время выполнения

ANALYZE — обновление статистики

# VACUUM собирает статистику, но часто нужно явно вызвать ANALYZE

ANALYZE;                           # Анализ всей БД
ANALYZE table_name;                # Анализ таблицы
VACUUM ANALYZE table_name;         # Оба сразу (рекомендуется)

# Статистика нужна для оптимизатора запросов
# Без актуальной статистики — плохие планы выполнения

EXPLAIN SELECT * FROM users WHERE id = 1;
# Результат: планы зависят от статистики ANALYZE

Практический пример: мониторинг и обслуживание

# PostgreSQL Python driver (psycopg2)
import psycopg2

conn = psycopg2.connect(
    dbname="mydb",
    user="postgres",
    password="password",
    host="localhost"
)
cur = conn.cursor()

# Проверить размер таблицы
cur.execute("""
    SELECT 
        schemaname,
        tablename,
        pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size
    FROM pg_tables
    WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
    ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;
""")

for row in cur.fetchall():
    print(f"{row[0]}.{row[1]}: {row[2]}")

# Запустить VACUUM для таблицы
print("Running VACUUM ANALYZE on users table...")
conn.autocommit = True  # VACUUM нужна отдельная транзакция
cur.execute("VACUUM ANALYZE users;")
print("Done!")

# Проверить последний вакуум
cur.execute("""
    SELECT 
        schemaname,
        relname,
        last_vacuum,
        last_autovacuum
    FROM pg_stat_user_tables
    ORDER BY last_vacuum DESC NULLS LAST;
""")

for row in cur.fetchall():
    print(f"Table {row[1]}: vacuum={row[2]}, autovacuum={row[3]}")

conn.close()

Проблемы с VACUUM

-- Проблема 1: VACUUM долго выполняется
-- Решение: запускать в низконагруженное время
VACUUM table_name;  -- Можно читать, но медленно

-- Проблема 2: VACUUM FULL блокирует таблицу
-- Решение: использовать pg_repack расширение
-- или просто VACUUM без FULL

-- Проблема 3: Много "dead tuples" — индекс раздут
-- Решение: переиндексировать
REINDEX TABLE table_name;

-- Проблема 4: Transaction ID wraparound
-- Если VACUUM не запускался долго, может быть критичная ошибка
-- Решение: запускать VACUUM регулярно (autovacuum должен это делать)

Когда VACUUM особенно важен

# 1. После массовых DELETE/UPDATE
for i in range(1000000):
    cursor.execute("DELETE FROM logs WHERE id = %s", (i,))
    if i % 10000 == 0:
        conn.commit()
        cursor.execute("VACUUM logs;")  # Периодически вакууми

# 2. После переноса данных
INSERT INTO new_table SELECT * FROM old_table;
DELETE FROM old_table;
VACUUM ANALYZE old_table;
VACUUM ANALYZE new_table;

# 3. Перед серьёзной переиндексацией
VACUUM FULL ANALYZE table_name;
REINDEX TABLE table_name;

Конфигурация в production

# postgresql.conf
autovacuum = on                           # Включить автовакуум
autovacuum_naptime = '30s'               # Проверять каждые 30 сек
autovacuum_vacuum_threshold = 50         # Вакуум если 50+ изменений
autovacuum_vacuum_scale_factor = 0.2     # + 20% от размера таблицы
autovacuum_vacuum_cost_delay = '10ms'    # Задержка между операциями
autovacuum_vacuum_cost_limit = 200       # Лимит операций/сек

# Для высоконагруженных систем
autovacuum_max_workers = 4               # Количество рабочих
autovacuum_work_mem = '256MB'            # Память для одного вакуума

Заключение

VACUUM — это не опциональная операция, а критическая часть обслуживания PostgreSQL. Она удаляет мёртвые версии строк, освобождает дисковое пространство и обновляет статистику. В production используй autovacuum, мониторь статистику VACUUM и периодически выполняй VACUUM ANALYZE для оптимальной производительности.