Postgresql - изменить размер столбца varchar - PullRequest
125 голосов
/ 11 октября 2011

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

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

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

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

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

Ответы [ 8 ]

75 голосов
/ 27 февраля 2015

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

http://www.postgresql.org/message-id/162867790801110710g3c686010qcdd852e721e7a559@mail.gmail.com

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) |
64 голосов
/ 12 октября 2011

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

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

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

44 голосов
/ 08 августа 2013

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

НЕТ НЕОБХОДИМОСТИ ИЗМЕНИТЬ КОЛОННУ В ВАШЕМ ДЕЛЕ!

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 .

31 голосов
/ 12 июня 2012

Я столкнулся с той же проблемой, пытаясь укоротить 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)

Как заметил @raylu,ALTER получает эксклюзивную блокировку таблицы, поэтому все другие операции будут отложены до ее завершения.

7 голосов
/ 18 марта 2014

Добавление нового столбца и замена нового на старый работал для меня, на 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 голосов
/ 10 апреля 2012

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

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

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

5 голосов
/ 20 октября 2016

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

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

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

1 голос
/ 24 февраля 2013

Я нашел очень простой способ изменить размер, то есть аннотацию @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),

.....

)
...