очень медленно расширять колонну варчар, почему? - PullRequest
0 голосов
/ 15 февраля 2011

Привет Нам нужно изменить столбец большой таблицы продуктов, обычно нормальные показатели ddl будут очень быстро, но вышеупомянутые ddl statmens занимают около 10 минут. Мне интересно знать причину! Я просто хочу расширить столбец varchar。 Ниже приведены подробности l

--table size
wapreader_log=> select pg_size_pretty(pg_relation_size('log_foot_mark'));
 pg_size_pretty 
----------------
 5441 MB
(1 row)


--table ddl
wapreader_log=> \d log_foot_mark
          Table "wapreader_log.log_foot_mark"
   Column    |            Type             | Modifiers 
-------------+-----------------------------+-----------
 id          | integer                     | not null
 create_time | timestamp without time zone | 
 sky_id      | integer                     | 
 url         | character varying(1000)     | 
 refer_url   | character varying(1000)     | 
 source      | character varying(64)       | 
 users       | character varying(64)       | 
 userm       | character varying(64)       | 
 usert       | character varying(64)       | 
 ip          | character varying(32)       | 
 module      | character varying(64)       | 
 resource_id | character varying(100)      | 
 user_agent  | character varying(128)      | 
Indexes:
    "pk_log_footmark" PRIMARY KEY, btree (id)


--alter column
wapreader_log=> \timing
Timing is on.

wapreader_log=>  ALTER TABLE wapreader_log.log_foot_mark ALTER column user_agent TYPE character varying(256); 
ALTER TABLE
Time: 603504.835 ms    

Ответы [ 4 ]

4 голосов
/ 15 февраля 2011

ALTER ... TYPE требует полного переписывания таблицы, поэтому на больших таблицах может потребоваться некоторое время.Если вам не нужно ограничение длины, тогда не используйте ограничение.Отбросьте эти ограничения раз и навсегда, и вы никогда не столкнетесь с новыми проблемами из-за устаревших ограничений.Просто используйте TEXT или VARCHAR.

3 голосов
/ 15 февраля 2011

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

Существуют некоторые типы изменений DDL, которые можно внести без создания второй копии таблицы, но это не одно из них. Например, вы можете быстро добавить новый столбец со значением NULL. Но добавление нового столбца с ненулевым значением по умолчанию требует создания новой копии.

0 голосов
/ 15 февраля 2011

Один из способов избежать перезаписи таблицы - это использовать домены SQL (см. CREATE DOMAIN) вместо varchars в вашей таблице. Затем вы можете добавлять и удалять ограничения для домена.

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

0 голосов
/ 15 февраля 2011

Не уверен, что это быстрее, но, возможно, вам придется проверить это.Попробуйте это до тех пор, пока PostgreSQL не сможет обработать требуемый тип изменения, не переписывая всю вонючую таблицу.

ALTER TABLE log_foot_mark RENAME refer_url TO refer_url_old;
ALTER TABLE log_foot_mark ADD COLUMN refer_url character varying(256);

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

WHILE (end < MAX_RECORDS)LOOP

BEGIN TRANSACTION;
UPDATE log_foot_mark
SET refer_url = refer_url_old
WHERE id >= start AND id <= end;

COMMIT TRANSACTION;
END LOOP;

ALTER TABLE log_foot_mark DROP COLUMN refer_url_old;

Имейте в виду, что логика цикла должна быть в чем-то отличном от PL \ PGSQL, чтобызаставить его совершить каждую итерацию цикла.Протестируйте его без всяких циклов и циклов с размером транзакции 10k 20k 30k и т. Д. До тех пор, пока не найдете подходящее место.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...