Здесь есть несколько недоразумений:
Нуль растровый является не частью заголовка кучи кортежа. По документации:
Существует заголовок фиксированного размера (занимающий 23 байта на большинстве машин), за которым следует необязательный нулевой битовый массив ...
Ваши 32 обнуляемых столбцов не подозрительны по двум причинам:
Пустое растровое изображение добавляется в строку и только в том случае, если в строке есть хотя бы одно фактическое NULL
значение . Обнуляемые столбцы не имеют прямого влияния, только фактические NULL
значения. Если нулевое растровое изображение выделено, оно всегда выделяется полностью (все или ничего). Фактический размер нулевого растрового изображения составляет 1 бит на столбец, округленный до следующего байта . По текущему коду
#define BITMAPLEN(NATTS) (((int)(NATTS) + 7) / 8)
Нулевое растровое изображение выделяется после заголовка кортежа кучи, за которым следует необязательный OID, а затем данные строки. Начало OID или данных строки указано t_hoff
в заголовке. За исходный код комментария :
Обратите внимание, что t_hoff должен быть кратным MAXALIGN.
После заголовка кортежа кучи есть один свободный байт, который занимает 23 байта. Таким образом, нулевое растровое изображение для строк до 8 столбцов эффективно предоставляется без дополнительных затрат. С 9-м столбцом в таблице t_hoff
добавляются еще один MAXALIGN
(обычно 8) байтов, чтобы обеспечить еще 64 столбца. Таким образом, следующая граница будет в 72 столбцах.
Чтобы отобразить управляющую информацию кластера базы данных PostgreSQL (вкл. MAXALIGN
), Пример типичной установки Postgres 9.3 на компьютере Debian:
sudo /usr/lib/postgresql/9.3/bin/pg_controldata /var/lib/postgresql/9.3/main
Я обновил инструкции в соответствующем ответе, который вы цитировали .
Помимо всего этого, даже если ваш ALTER TABLE
оператор вызывает перезапись всей таблицы (что, вероятно, и происходит, изменяя тип данных), 250 КБ - это на самом деле не так много, и это будет считаться секундами на любой приличной машине (если строки не слишком большие) , 10 и более минут указывают на совершенно другую проблему. Ваше заявление ожидает блокировки на столе, скорее всего.
Растущее число записей в pg_stat_activity
означает больше открытых транзакций - указывает на одновременный доступ к таблице (скорее всего), который должен ждать завершения операции.
Несколько снимков в темноте
Проверьте наличие возможного раздувания таблиц, попробуйте осторожный VACUUM mytable
или более агрессивный VACUUM FULL mytable
- который может столкнуться с теми же проблемами параллелизма, поскольку эта форма также получает эксклюзивную блокировку. Вместо этого вы можете попробовать pg_repack ...
Я бы начал с изучения возможных проблем с индексами, триггерами, внешним ключом или другими ограничениями, особенно теми, которые касаются столбца. Особенно поврежденный индекс может быть вовлечен? Попробуйте REINDEX TABLE mytable;
или DROP
все из них и повторно добавьте их после ALTER TABLE
в той же транзакции .
Попробуйте выполнить команду ночью или всякий раз, когда нет большой нагрузки.
Методом грубой силы будет остановить доступ к серверу, а затем повторите попытку:
Не имея возможности определить это, обновление до текущей версии или, в частности, до 9.4 может помочь. Было несколько улучшений для больших таблиц и для блокировки деталей. Но если в вашей БД что-то сломано, вам, вероятно, следует сначала это выяснить.
SET NOT NULL
не менее, не изменяет тип, он просто добавляет ограничение - но ограничение должно быть проверено по таблице, а для этого требуется полное сканирование таблицы. 9.4 улучшает некоторые из этих случаев, используя более слабые блокировки, но все еще довольно тяжелый.