У меня проблемы с добавлением нового столбца в таблицу.
Я пытался запустить его пару раз, но после более 10 минут работы решил отменить запрос из-за времени блокировки.
ALTER TABLE mytable ADD mycolumn VARCHAR(50);
Полезная информация:
- Версия PostgreSQL: 9.1
- Количество рядов: ~ 250К
- Количество столбцов: 38
- Количество обнуляемых столбцов: 32
- Количество ограничений: 5 (1 ПК, 3 ФК, 1 УНИКАЛЬНЫЙ)
- Количество индексов: 1
- Тип ОС: Debian Squeeze 64
Я нашел интересную информацию о том, как PostgreSQL управляет обнуляемыми столбцами (через HeapTupleHeader).
Мое первое предположение состоит в том, что, поскольку в этой таблице уже есть 32 столбца с 8-разрядными значениями MAXALIGN
, которые можно обнулять, длина HeapTupleHeader составляет 4 байта (не проверено, и я не знаю, как это сделать).
Таким образом, добавление нового столбца, который может содержать пустые значения, может потребовать обновления HeapTupleHeader в каждой строке, чтобы добавить новые 8-битные значения MAXALIGN
, что может вызвать проблемы с производительностью.
Поэтому я попытался изменить один из столбцов, допускающих значение NULL, (которые на самом деле не могут иметь значение NULL), чтобы уменьшить количество столбцов, которые могут быть NULL, до 31, чтобы проверить, может ли мое предположение быть верным.
ALTER TABLE mytable ALTER myothercolumn SET NOT NULL;
К сожалению, это изменение также занимает очень много времени, более 5 минут, поэтому я также прервал его.
У вас есть представление о том, что может привести к снижению производительности?
источник
SET NOT NULL
не менее, не изменяет тип, он просто добавляет ограничение - но ограничение должно быть проверено по таблице, а для этого требуется полное сканирование таблицы. 9.4 улучшает некоторые из этих случаев, используя более слабые блокировки, но все еще довольно тяжелый.Ответы:
Здесь есть несколько недоразумений:
Нуль растровый является не частью заголовка кучи кортежа. По документации:
Ваши 32 обнуляемых столбцов не подозрительны по двум причинам:
Пустое растровое изображение добавляется в строку и только в том случае, если в строке есть хотя бы одно фактическое
NULL
значение . Обнуляемые столбцы не имеют прямого влияния, только фактическиеNULL
значения. Если нулевое растровое изображение выделено, оно всегда выделяется полностью (все или ничего). Фактический размер нулевого растрового изображения составляет 1 бит на столбец, округленный до следующего байта . По текущему кодуНулевое растровое изображение выделяется после заголовка кортежа кучи, за которым следует необязательный OID, а затем данные строки. Начало OID или данных строки указано
t_hoff
в заголовке. За исходный код комментария :После заголовка кортежа кучи есть один свободный байт, который занимает 23 байта. Таким образом, нулевое растровое изображение для строк до 8 столбцов эффективно предоставляется без дополнительных затрат. С 9-м столбцом в таблице
t_hoff
добавляются еще одинMAXALIGN
(обычно 8) байтов, чтобы обеспечить еще 64 столбца. Таким образом, следующая граница будет в 72 столбцах.Чтобы отобразить управляющую информацию кластера базы данных PostgreSQL (вкл.
MAXALIGN
), Пример типичной установки Postgres 9.3 на компьютере Debian:Я обновил инструкции в соответствующем ответе, который вы цитировали .
Помимо всего этого, даже если ваш
ALTER TABLE
оператор вызывает перезапись всей таблицы (что, вероятно, и происходит, изменяя тип данных), 250 КБ - это на самом деле не так много, и это будет считаться секундами на любой приличной машине (если строки не слишком большие) , 10 и более минут указывают на совершенно другую проблему. Ваше заявление ожидает блокировки на столе, скорее всего.Растущее число записей в
pg_stat_activity
означает больше открытых транзакций - указывает на одновременный доступ к таблице (скорее всего), который должен ждать завершения операции.Несколько снимков в темноте
Проверьте наличие возможного раздувания таблиц, попробуйте осторожный
VACUUM mytable
или более агрессивныйVACUUM FULL mytable
- который может столкнуться с теми же проблемами параллелизма, поскольку эта форма также получает эксклюзивную блокировку. Вместо этого вы можете попробовать pg_repack ...Я бы начал с изучения возможных проблем с индексами, триггерами, внешним ключом или другими ограничениями, особенно теми, которые касаются столбца. Особенно поврежденный индекс может быть вовлечен? Попробуйте
REINDEX TABLE mytable;
илиDROP
все из них и повторно добавьте их послеALTER TABLE
в той же транзакции .Попробуйте выполнить команду ночью или всякий раз, когда нет большой нагрузки.
Методом грубой силы будет остановить доступ к серверу, а затем повторите попытку:
Не имея возможности определить это, обновление до текущей версии или, в частности, до 9.4 может помочь. Было несколько улучшений для больших таблиц и для блокировки деталей. Но если в вашей БД что-то сломано, вам, вероятно, следует сначала это выяснить.
источник