Удаленные поля???

lionson
Дата: 15.09.2004 15:03:16
Столкнулся с таким явлением

При удалении поля в таблице информация о нем остается в системной таблице
pg_attribute в виде некоего уведомления, что оно pg.dropped+oid
В результате чего в один прекрасный момен при попытке добавить очередное поле получил сообщение, что кол-во полей не может превышать 1600 штук.

Вакуумы не помогли.

Можно ли уничтожить эти останки официальным путем, не прибегая к прямой чистке таблицы pg_attribute?
assa
Дата: 15.09.2004 17:14:34
и действительно:
SELECT DISTINCT a.attnum, (a.attname)::varchar(64) AS field , a.attisdropped as dropped
FROM pg_class c, pg_attribute a
/*, pg_type t */
WHERE c.relname = 'test' and a.attnum > 0 and a.attrelid = c.oid
/* and a.atttypid = t.oid */
ORDER BY a.attnum;

получаю:

attnum	field				dropped
1	id				0
2	name				0
3	........pg.dropped.3........	1
4	........pg.dropped.4........	1
пока вакуумы ни только таблицы, ни всей базы не вспомогли
assa
Дата: 15.09.2004 17:23:42
Аллё, ХУРУ!

есть ли штатный бубен окромя прямого лома:
DELETE  FROM pg_attribute 
WHERE 
  attisdropped=TRUE ;

и чем грозит такой лом (поддерживается ли логическая/ссылочная целостность на уровне системных таблиц? Нужно ли будет выискивать непочищенные записи?)

Да, версия ПГ 7.3.4.
assa
Дата: 15.09.2004 18:02:44
так-с! "прямой лом" кажисть сковыривает мозги напрочь. Получаю ошибку:

ERROR: Catalog is missing 2 attribute(s) For relid xxxxx

табличку нельзя ни дропнуть, ни достучаться до данных.

(карашо что и база и табла тестовые)
assa
Дата: 15.09.2004 18:55:19
что исчо сделать, чтобы работало - не понял. (возможно, не заработает по-любому, если физически из таблицы столбцы не дропаются - тогда кроме пересоздания таблиц со всеми связями (но без дропнутых столбцов) - никак???)

Пока починил руками - вставил нужное кол-во записей в pg_attribute
запросами, после этого дропнул и создал тестовую табличку "test" наново.

PS ^
запросы вида:
INSERT INTO pg_catalog.pg_attribute
(
  attrelid ,
  attname ,
  atttypid,
  attstattarget ,
  attlen ,
  attnum ,
  attndims ,
  attcacheoff ,
  atttypmod ,
  attbyval ,
  attstorage ,
  attisset ,
  attalign ,
  attnotnull ,
  atthasdef ,
  attisdropped ,
  attislocal ,
  attinhcount 
)

SELECT  

  318597::oid AS attrelid ,
  '........pg.dropped.4........' ,
  atttypid,
  attstattarget ,
  attlen ,
  4 AS attnum ,
  attndims ,
  attcacheoff ,
  atttypmod ,
  attbyval ,
  attstorage ,
  attisset ,
  attalign ,
  attnotnull ,
  atthasdef ,
  TRUE as attisdropped ,
  attislocal ,
  attinhcount 
FROM  pg_attribute a

WHERE  a.attnum > 0 and a.attrelid = 318597
 
AND attname='name' /* тот -же тип */
ORDER BY a.attnum;
;
, мдя
vadimm
Дата: 15.09.2004 21:26:10
Тоже сталкивался с такой проблемой и ничего лучше чем удалить и пересоздать наново не нашёл, а это очень неудобно. Присодиняюсь к задавшему вопрос:
Можно ли уничтожить эти останки официальным путем ? Помогите
assa
Дата: 16.09.2004 11:06:43
Проверил:
колонки физически не убираются из таблиц (и данные в них остаются). Т.е. таблицы "тяжелеют" из-за дропнутых колонок.

тестировал так:
1.создал поле в таблице test
ALTER TABLE public.test ADD COLUMN new1 text;
2.разместил в нем данные
3. удалил поле
ALTER TABLE public.test DROP COLUMN new1;

4. Нашел имя и тип удаленного поля:
SELECT DISTINCT a.attnum, (a.attname)::varchar(64) AS field , a.attisdropped as dropped, c.oid, a.atttypid
FROM pg_class c, pg_attribute a
/*, pg_type t */
WHERE c.relname = 'test' and a.attnum > 0 and a.attrelid = c.oid
AND c.oid = 444889
/* and a.atttypid = t.oid */
ORDER BY a.attnum;

тут ' AND c.oid = 444889 - т.к. в pg_catalog видны таблицы всех баз - отделяю только мою.

5. на всякий случай убедился, что удаленные только мои колонки
SELECT *
FROM pg_attribute
WHERE
attisdropped=TRUE ;

6 "Восстановил" признак неудаленности и тип поля (для отображения)

UPDATE pg_attribute
SET attisdropped = FALSE, atttypid = 25
WHERE
attname = '........pg.dropped.3........';

7. Просмотрел данные в "удаленном столбце" - они на месте.


Итак при DROP COLUMN скорее всего не происходит физического удаления столбца, он лишь помечается как удаленный и имеющий 0-й тип(и вследствии этого перестает возвращаться запросами), но для чтения таблиц видимо важно соответствие описания в каталоге их физической структуре (т.е. описатели удаленных столбцов удалять руками нельзя). Это позволяет добраться (предложенным методом взлома) к данным "удаленных" столбцов, но вряд ли это то, что ожидается юзером от инструкции DROP COLUMN. Получается, что единственный способ избавиться от наследия - пересоздать таблицу со всей логической обвязкой (например поднять полный дамп базы).
Или я что-то пропустил?
hastler
Дата: 16.09.2004 23:42:07
Столько действий проделали, а доку почитать влом?

http://www.postgresql.org/docs/7.4/interactive/sql-altertable.html
...
The DROP COLUMN form does not physically remove the column, but simply makes it invisible to SQL operations. Subsequent insert and update operations in the table will store a null value for the column. Thus, dropping a column is quick but it will not immediately reduce the on-disk size of your table, as the space occupied by the dropped column is not reclaimed. The space will be reclaimed over time as existing rows are updated. To reclaim the space at once, do a dummy UPDATE of all rows and then vacuum, as in:

UPDATE table SET col = col;
VACUUM FULL table;
vadimm
Дата: 17.09.2004 11:46:27
Я тоже это читал, но на деле поле всё равно остаётся или я что то не так делаю ?
CREATE TABLE A
(
  F1 int4 ,
  F2 int4 
);

alter table a drop f2;

SELECT attname
FROM pg_attribute
WHERE
attisdropped=TRUE ;
результат
........pg.dropped.2........
далее
UPDATE a SET f1 = f1;
VACUUM FULL a;

SELECT attname
FROM pg_attribute
WHERE
attisdropped=TRUE ;
результат
........pg.dropped.2........
всё на месте !!!
vadimm
Дата: 17.09.2004 11:48:44
Я тоже это читал, но на деле поле всё равно остаётся или я что то не так делаю ?
CREATE TABLE A
(
  F1 int4 ,
  F2 int4 
);

alter table a drop f2;

SELECT attname
FROM pg_attribute
WHERE
attisdropped=TRUE ;
результат
........pg.dropped.2........
далее
UPDATE a SET f1 = f1;
VACUUM FULL a;

SELECT attname
FROM pg_attribute
WHERE
attisdropped=TRUE ;
результат
........pg.dropped.2........
всё на месте !!!