Postgresql - изменить размер столбца varchar

У меня есть вопрос о команде ALTER TABLE на действительно большой таблице (почти 30 миллионов строк). Один из его столбцов - varchar(255), и я хотел бы изменить его размер до varchar(40). В принципе, я хотел бы изменить свой столбец, выполнив следующую команду:

ALTER TABLE mytable ALTER COLUMN mycolumn TYPE varchar(40);

У меня нет проблем, если процесс очень длинный, но кажется, что моя таблица не читается во время команды ALTER TABLE. Есть ли более разумный способ? Может быть, добавить новый столбец, скопировать значения из старого столбца, удалить старый столбец и, наконец, переименовать новый?

Любая подсказка будет принята с благодарностью! Спасибо заранее,

Примечание. Я использую PostgreSQL 9.0.

Ответ 1

Здесь описано, как это сделать при Изменить размер столбца в таблице PostgreSQL без изменения данных. Вы должны взломать данные каталога базы данных. Единственный способ сделать это официально - это ALTER TABLE, и поскольку вы заметили, что изменения будут блокировать и переписывать всю таблицу во время ее работы.

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

VARCHAR - ужасный тип, который существует в PostgreSQL только для соответствия его связанной ужасной части стандарта SQL. Если вам не нужна совместимость с несколькими базами данных, рассмотрите возможность хранения ваших данных как ТЕКСТ и добавьте ограничение, чтобы ограничить его длину. Ограничения, которые вы можете изменить без этой проблемы с блокировкой/перезаписи таблицы, и они могут выполнять большую проверку целостности, чем проверку слабой длины.

Ответ 2

В PostgreSQL 9.1 есть более простой способ

http://www.postgresql.org/message-id/[email protected]

CREATE TABLE foog(a varchar(10));

ALTER TABLE foog ALTER COLUMN a TYPE varchar(30);

postgres=# \d foog

 Table "public.foog"
 Column |         Type          | Modifiers
--------+-----------------------+-----------
 a      | character varying(30) |

Ответ 3

Хорошо, я, наверное, опаздываю на вечеринку, НО...

НЕТ НУЖНО УДАЛИТЬ КОЛОНКУ В ВАШЕМ СЛУЧАЕ!

Postgres, в отличие от некоторых других баз данных, достаточно умен, чтобы использовать только достаточно места для установки строки (даже с использованием сжатия для более длинных строк), поэтому даже если ваш столбец объявлен как VARCHAR (255) - если вы храните 40- символьные строки в столбце, использование пространства должно составлять 40 байтов + 1 байт служебных данных.

Требование к хранению короткой строки (до 126 байтов) - 1 байт плюс фактическая строка, которая включает пробел в корпусе характера. Более длинные строки имеют 4 байта служебных данных вместо 1. Длинные строки автоматически сжимаются системой, поэтому физическое требование на диске может быть меньше. Очень длинные значения также хранятся в фоновых таблицах, чтобы они не мешали быстрому доступ к более коротким значениям столбцов.

(http://www.postgresql.org/docs/9.0/interactive/datatype-character.html)

Спецификация размера в VARCHAR используется только для проверки размера вставленных значений, это не влияет на расположение диска. Фактически, поля VARCHAR и TEXT сохраняются таким же образом в Postgres.

Ответ 4

Я столкнулся с такой же проблемой, пытаясь обрезать VARCHAR с 32 до 8 и получить ERROR: value too long for type character varying(8). Я хочу как можно ближе подойти к SQL, потому что я использую самодельную структуру JPA, которая, возможно, придется переключать на разные СУБД в соответствии с выборами клиентов (по умолчанию PostgreSQL). Следовательно, я не хочу использовать трюк изменения системных таблиц.

Я закончил использование инструкции USING в ALTER TABLE:

ALTER TABLE "MY_TABLE" ALTER COLUMN "MyColumn" TYPE varchar(8)
USING substr("MyColumn", 1, 8)

Я действительно не рассматривал последствия, если к таблице обращается другая программа или индексируется таблица. Я предполагаю, что Postgres делает это автоматически?

Ответ 5

Здесь кеш страницы, описанной Грегом Смитом. В случае, если это также умирает, инструкция alter выглядит так:

UPDATE pg_attribute SET atttypmod = 35+4
WHERE attrelid = 'TABLE1'::regclass
AND attname = 'COL1';

Если ваша таблица TABLE1, столбец COL1 и вы хотите установить его на 35 символов (+4 необходимо для устаревших целей в соответствии со ссылкой, возможно, служебные данные, на которые ссылается AH в комментариях).

Ответ 6

Добавление нового столбца и замена нового со старыми работами для меня, на redshift postgresql, см. эту ссылку для более подробной информации https://gist.github.com/mmasashi/7107430

BEGIN;
LOCK users;
ALTER TABLE users ADD COLUMN name_new varchar(512) DEFAULT NULL;
UPDATE users SET name_new = name;
ALTER TABLE users DROP name;
ALTER TABLE users RENAME name_new TO name;
END;

Ответ 7

если вы поместили alter в транзакцию, таблица не должна быть заблокирована:

BEGIN;
  ALTER TABLE "public"."mytable" ALTER COLUMN "mycolumn" TYPE varchar(40);
COMMIT;

это сработало для меня быстро, несколько секунд на столе с более чем 400 тыс. строк.

Ответ 8

Я нашел очень простой способ изменить размер, т.е. аннотацию @Size (min = 1, max = 50), которая является частью "import javax.validation.constraints", т.е. "import javax.validation.constraints.Size;"

@Size(min = 1, max = 50)
private String country;


when executing  this is hibernate you get in pgAdmin III 


CREATE TABLE address
(
.....
  country character varying(50),

.....

)