Перейти к содержанию

Сопровождение таблиц и статистики

После редактирования карточек таблица продолжает показывать шесть курсов. Но физическое состояние базы не сводится к COUNT: PostgreSQL сохраняет версии строк для одновременной работы транзакций, а планировщик использует статистическое представление данных. Обслуживание помогает системе поддерживать это состояние, не изменяя предметный смысл каталога.

В уроке используется PostgreSQL 17.11 и самостоятельный снимок catalog-db-advanced/lesson-31 из архива продолжения. Команды обслуживания, изменения данных и EXPLAIN не выполнялись. Мы подготовим маленькую последовательность для будущего ручного рассмотрения, но не будем назначать шести строкам выдуманное число dead tuples или обещанное ускорение.

Видимые данные и старые версии

Когда UPDATE меняет цену курса, другие транзакции могут ещё нуждаться в предыдущем состоянии. Поэтому старая версия не исчезает немедленно лишь потому, что клиент увидел UPDATE 1. Ранее мы наблюдали это через снимок Repeatable Read: читатель продолжал видеть исходную цену после фиксации другой сессии.

Для отдельного опыта подготовлен churn.sql. Он двумя завершёнными транзакциями увеличивает цену JavaScript на единицу и возвращает её обратно:

BEGIN;
UPDATE catalog.courses
SET price = price + 1, version = version + 1
WHERE id = 2;
COMMIT;

BEGIN;
UPDATE catalog.courses
SET price = price - 1, version = version + 1
WHERE id = 2;
COMMIT;

При исходных price 1990 и version 1 ожидаем конечную цену 1990 и версию 3. Мы сохранили два изменения, а не откатили их. Поэтому прикладная версия выросла, хотя видимая цена снова равна исходной. Число карточек и уроков не увеличивается: UPDATE изменяет существующий объект.

Из этого нельзя вывести точное значение счётчика мёртвых строк. Физический путь изменений, состояние других транзакций и фоновое обслуживание влияют на наблюдение. Даже если учебные SQL одинаковы, статистический экран двух лабораторий может отличаться. Здесь полезно различить гарантированное предметное значение version и диагностическую оценку накопленного состояния.

Что показывает статистика

Сначала посмотрим представление pg_stat_user_tables:

SELECT relname, n_live_tup, n_dead_tup,
       last_vacuum, last_autovacuum, last_analyze
FROM pg_stat_user_tables
WHERE schemaname = 'catalog'
ORDER BY relname;

Оно связывает таблицу с оценками и отметками обслуживания. n_live_tup и n_dead_tup не заменяют точный SELECT COUNT(*) для ответа пользователю каталога. Значение last_autovacuum показывает известную отметку соответствующей деятельности, а пустое поле не доказывает, что вообще никогда не происходило никакого обслуживания во всей истории экземпляра.

Система накопительной статистики описана в руководстве PostgreSQL. Для диагностики важно знать момент наблюдения и состояние соединения. Нельзя прочитать одно значение, затем изменить данные и объявить первое число актуальным отчётом о второй ситуации. В длинной транзакции нужно также учитывать правила получения и кеширования статистической информации.

Текст урока не содержит искусственного вывода этих колонок. При будущем ручном рассмотрении запишите реальные значения до и после выбранного действия. Если autovacuum сработал между чтениями, это нормальная часть объяснения, а не повод скрыть неудобный результат. Маленький пример учит читать происхождение показателя, а не подгонять его под заранее нарисованную таблицу.

VACUUM и ANALYZE

Обычный VACUUM помогает убрать версии, которые больше не нужны активным снимкам, и сделать занимаемое ими место пригодным для дальнейшего использования. ANALYZE собирает статистику содержимого для планировщика. Эти задачи связаны обслуживанием, но имеют разные результаты: освобождённое внутреннее место не равно новой гистограмме значений.

Подготовленная команда соединяет их для одной таблицы:

VACUUM (ANALYZE) catalog.courses;

Выполнять её следует отдельной командой вне BEGIN. В отличие от большинства примеров изменения данных, maintenance.sql не запускается с --single-transaction. VACUUM запрещён внутри transaction block; оборачивание всех административных действий в общую транзакцию не является универсальным правилом. Ограничения команды и необходимые права указаны в VACUUM.

Учебный student владеет таблицей. Ограниченная роль публичного чтения из предыдущего урока такой обязанностью не наделяется. Обслуживание рассматривается через отдельного ответственного владельца, а не добавляется в обычный запрос каталога при каждом открытии страницы. Иначе задержка административной операции становится непредсказуемой частью пользовательского интерфейса.

Почему файл не обязан уменьшиться

Обычная очистка обычно делает место доступным для повторного использования внутри таблицы. Из этого не следует обязательное сокращение файла на диске на заранее известное число байт. Для растущего каталога внутреннее повторное использование может быть вполне полезным: новые версии занимают подготовленное место вместо бесконечного увеличения объёма.

VACUUM FULL переписывает таблицу и использует более сильную блокировку. Это другая операция с другим влиянием на доступность и временные ресурсы. Она не включена в наш файл и не предлагается как ежедневная «кнопка ускорения». Основные причины обслуживания и различия вариантов объясняются в разделе о регулярной очистке.

Длинная открытая транзакция способна сохранять старый снимок, которому ещё нужны предыдущие версии. Тогда простое повторение команды обслуживания не устраняет причину удержания данных. Нужно найти, почему приложение держит соединение в транзакции, и завершать операции в разумной границе. Редакторская форма, открытая на время человеческого размышления, должна хранить version в интерфейсе, а не держать BEGIN в пуле.

Как связать наблюдение с причиной

Представим, что карточка стала открываться медленно после большого редакционного импорта. Само совпадение по времени ещё не доказывает недостаток VACUUM. Запрос может ждать блокировку, соединение может ждать место в пуле, а шаблон страницы может обращаться к внешнему ресурсу. Для обслуживания нужна связь между наблюдаемым этапом и состоянием конкретной таблицы.

Поэтому будущую диагностику удобно вести от пользовательской операции к её этапам. Если задержка до выдачи соединения, начните с границы владения ресурсом. Если SQL ждёт чужой transaction, выясните, почему он остаётся открытым. Если рассматривается выбор плана, отдельно оцените актуальность статистики и распределение данных. Один административный вызов не отвечает на все три вопроса.

У нашего churn нет массовой нагрузки, и даже точное ручное измерение этого опыта не позволило бы назначить график обслуживания большому сайту. Практический график зависит от интенсивности записей и состояния экземпляра. Смысл подготовленного урока — понять, какие значения гарантированы предметной операцией, какие показатели оценочные и почему освобождение старых версий относится к общей работе системы. Тогда дальнейшее наблюдение даст причину следующего действия, а не повод повторять знакомую команду без анализа.

Статистика и план запроса

В lesson.sql подготовлен EXPLAIN без ANALYZE для обычного фильтра опубликованных frontend-курсов. Будущее чтение показывает выбранную стратегию, а не фактическое выполнение и время. После обновления статистики план может измениться или остаться прежним. Оба случая объясняются оценками и размером данных; смена слова в плане не служит самостоятельной метрикой качества.

Для шести курсов последовательное чтение не является провалом обслуживания или доказательством ненужности ранее обсуждавшегося индекса. Планировщик выбирает путь для конкретного набора и условий. Если завтра библиотека станет существенно больше, понадобится другая оценка распределения, фильтров и стоимости записи. Учебное число страниц плана роста не подменяет реальную статистику таблицы.

Фоновый autovacuum существует именно для регулярной работы, а не только для момента, когда администратор вспомнил о базе. Его не следует отключать ради красивого сравнения двух снимков. Кроме повторного использования пространства есть задачи сохранения работоспособности механизма идентификаторов транзакций. В упражнении настройки экземпляра не меняются: обсуждаем наблюдение, а не проводим административный эксперимент на неизвестной нагрузке.

После будущего ручного обслуживания предметная сверка всё ещё должна показывать шесть курсов и прежние связи. Если churn запускался, JavaScript имеет цену 1990 и version 3; если не запускался, version 1. Эта условная граница помогает объяснить результат честно. Теперь у каталога есть не только запросы чтения и правки, но и понятные обязанности по поддержанию базы между ними.

Оглавление курса.