← Назад к вопросам
Что делает оператор 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 для оптимальной производительности.