为什么我的 table 从 pg_catalog.pg_class 中消失了? (或者,如何找到主键列?)
Why did my table disappear from pg_catalog.pg_class? (Alternatively, how to find primary key columns?)
使用来自 debian 的 postgres 10.4.2(实际上,使用 postgresql docker 容器。)
我按顺序应用了一些架构文件。这些创建、删除和更改 tables 以跟随架构随时间的演变。
然后,我 运行 一个程序,它从 pg_catalog 中选择 table 定义来为现有的 table 生成代码包装器。到目前为止,这一直很好。 (该程序的代码是我开发的,因此非常值得怀疑!)
我最近将 "alter table customer add field customer_stem varchar(255) not null default ''" 和 "create index on customer(customer_stem)" 添加到一个新的架构文件中。
现在,在查找主键的 table 的查询中不再找到客户 table。
我运行的查询是这样的:
select c.relname, i.indkey
from pg_catalog.pg_index i
inner join pg_catalog.pg_class c
on i.indrelid=c.relfilenode
inner join pg_catalog.pg_tables t
on c.relname=t.tablename
where t.schemaname='public'
and i.indisprimary;
这应该会告诉我哪些索引是我的 table 的主键。
但是,"customer" table 现在不在该查询范围内——pg_class 中的 relfilenode
不再匹配 pg_index.
中的任何内容
# select relname, relfilenode from pg_catalog.pg_class where relname='customer';
relname | relfilenode
----------+-------------
customer | 16512
observe_dev=# select count(1) from pg_catalog.pg_index where indrelid=16512;
count
-------
0
(1 row)
这个 table!
应该有一个主键和一个二级索引
所以,我的猜测是 "alter table" 语句以某种方式更改了 'customer' class 的 ID,使其不再匹配 "pg_index" table,但这看起来真的很奇怪。 PSQL 仍然知道定义是什么:
Table "public.customer"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
---------------+------------------------+-----------+----------+-----------------------+----------+--------------+-------------
customer_id | integer | | not null | | plain | |
customer_name | character varying(255) | | not null | | extended | |
customer_stem | character varying(255) | | not null | ''::character varying | extended | |
Indexes:
"customer_pkey" PRIMARY KEY, btree (customer_id)
"customer_customer_name_idx" btree (customer_name)
"customer_customer_stem_idx" btree (customer_stem)
Referenced by:
也有一些外键关系。
因此,发生了以下两种情况之一:
1) alter table 以某种方式导致 pg_catalog 停止更新(这似乎不太可能。)
2) 我对如何找到每个 table 的主键列的研究是错误的,我看错了 tables/columns
很可能是 2),但如果是这样,我应该如何找到该信息?
我认为您可能应该在 pg_class.oid
栏中加入 pg_index
,即:
select c.relname, i.indkey
from pg_catalog.pg_index i
inner join pg_catalog.pg_class c
on i.indrelid=c.oid -- << HERE change c.relfilenode to c.oid
left join pg_catalog.pg_tables t
on c.relname=t.tablename
where t.schemaname='public'
and i.indisprimary;
请注意,oid
在 select * from pg_catalog.pg_class
和 \d pg_catalog.pg_class
的输出中隐藏在 psql
中,但它作为 "hidden" 列存在。
我能够在本地复制您的问题,所以我猜测添加列或索引会更改 table 的 pg_class
记录中 relfilenode
的值。
另请参阅 https://wiki.postgresql.org/wiki/Retrieve_primary_key_columns,其中详细介绍了如何查询主键 - 可能值得在 pg_attribute
的连接中添加。有点 OT,但我发现值得注意的是 'my_table_name'::regclass
被 PostgreSQL 转换为适当的 pg_class.oid
。您实际上可以通过 运行 select 'my_table_name'::regclass::oid
!
进行测试(并获得任何 table 的 oid
)
出于兴趣,我还做了一些进一步的测试,以确定是哪个 table 更改触发了 pg_class.relfilenode
更改。看来 alter table add column ...
default ''` 是原因。
在未指定 default
的情况下添加列时,该值保持不变。以下脚本演示了该行为:
create table test (id uuid, col1 varchar(255));
select c.oid, c.relfilenode, c.relname from pg_catalog.pg_class c where c.oid = 'test'::regclass;
alter table test add column col2 varchar(255) not null;
select c.oid, c.relfilenode, c.relname from pg_catalog.pg_class c where c.oid = 'test'::regclass;
alter table test add column col3 varchar(255) not null default '';
select c.oid, c.relfilenode, c.relname from pg_catalog.pg_class c where c.oid = 'test'::regclass;
drop table test;
因此,由于某种原因,添加具有默认值的列似乎会更改关系的文件节点。关于 relfilenode
和其他属性的更多详细信息,也值得阅读 PostgreSQL docs on pg_class
。
不要在名字文本上加入目录,你只需要数字id就可以加入(目录中的名字是区分大小写的,这只会让你感到困惑) .另外:您不需要 pg_tables 目录;这只是 pg_class
上的一个视图
WRT 消失的目录条目:您是否提交了您的变更 table DDL? DDL 需要对目录执行一些技巧以对其他会话隐藏新版本。
select c.relname, i.indkey,i.indexrelid , i.indrelid
from pg_catalog.pg_index i
inner join pg_catalog.pg_class c
on i.indrelid=c.relfilenode
where c.relname='target';
使用来自 debian 的 postgres 10.4.2(实际上,使用 postgresql docker 容器。)
我按顺序应用了一些架构文件。这些创建、删除和更改 tables 以跟随架构随时间的演变。
然后,我 运行 一个程序,它从 pg_catalog 中选择 table 定义来为现有的 table 生成代码包装器。到目前为止,这一直很好。 (该程序的代码是我开发的,因此非常值得怀疑!)
我最近将 "alter table customer add field customer_stem varchar(255) not null default ''" 和 "create index on customer(customer_stem)" 添加到一个新的架构文件中。 现在,在查找主键的 table 的查询中不再找到客户 table。
我运行的查询是这样的:
select c.relname, i.indkey
from pg_catalog.pg_index i
inner join pg_catalog.pg_class c
on i.indrelid=c.relfilenode
inner join pg_catalog.pg_tables t
on c.relname=t.tablename
where t.schemaname='public'
and i.indisprimary;
这应该会告诉我哪些索引是我的 table 的主键。
但是,"customer" table 现在不在该查询范围内——pg_class 中的 relfilenode
不再匹配 pg_index.
# select relname, relfilenode from pg_catalog.pg_class where relname='customer';
relname | relfilenode
----------+-------------
customer | 16512
observe_dev=# select count(1) from pg_catalog.pg_index where indrelid=16512;
count
-------
0
(1 row)
这个 table!
应该有一个主键和一个二级索引所以,我的猜测是 "alter table" 语句以某种方式更改了 'customer' class 的 ID,使其不再匹配 "pg_index" table,但这看起来真的很奇怪。 PSQL 仍然知道定义是什么:
Table "public.customer"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
---------------+------------------------+-----------+----------+-----------------------+----------+--------------+-------------
customer_id | integer | | not null | | plain | |
customer_name | character varying(255) | | not null | | extended | |
customer_stem | character varying(255) | | not null | ''::character varying | extended | |
Indexes:
"customer_pkey" PRIMARY KEY, btree (customer_id)
"customer_customer_name_idx" btree (customer_name)
"customer_customer_stem_idx" btree (customer_stem)
Referenced by:
也有一些外键关系。
因此,发生了以下两种情况之一: 1) alter table 以某种方式导致 pg_catalog 停止更新(这似乎不太可能。) 2) 我对如何找到每个 table 的主键列的研究是错误的,我看错了 tables/columns
很可能是 2),但如果是这样,我应该如何找到该信息?
我认为您可能应该在 pg_class.oid
栏中加入 pg_index
,即:
select c.relname, i.indkey
from pg_catalog.pg_index i
inner join pg_catalog.pg_class c
on i.indrelid=c.oid -- << HERE change c.relfilenode to c.oid
left join pg_catalog.pg_tables t
on c.relname=t.tablename
where t.schemaname='public'
and i.indisprimary;
请注意,oid
在 select * from pg_catalog.pg_class
和 \d pg_catalog.pg_class
的输出中隐藏在 psql
中,但它作为 "hidden" 列存在。
我能够在本地复制您的问题,所以我猜测添加列或索引会更改 table 的 pg_class
记录中 relfilenode
的值。
另请参阅 https://wiki.postgresql.org/wiki/Retrieve_primary_key_columns,其中详细介绍了如何查询主键 - 可能值得在 pg_attribute
的连接中添加。有点 OT,但我发现值得注意的是 'my_table_name'::regclass
被 PostgreSQL 转换为适当的 pg_class.oid
。您实际上可以通过 运行 select 'my_table_name'::regclass::oid
!
oid
)
出于兴趣,我还做了一些进一步的测试,以确定是哪个 table 更改触发了 pg_class.relfilenode
更改。看来 alter table add column ...
default ''` 是原因。
在未指定 default
的情况下添加列时,该值保持不变。以下脚本演示了该行为:
create table test (id uuid, col1 varchar(255));
select c.oid, c.relfilenode, c.relname from pg_catalog.pg_class c where c.oid = 'test'::regclass;
alter table test add column col2 varchar(255) not null;
select c.oid, c.relfilenode, c.relname from pg_catalog.pg_class c where c.oid = 'test'::regclass;
alter table test add column col3 varchar(255) not null default '';
select c.oid, c.relfilenode, c.relname from pg_catalog.pg_class c where c.oid = 'test'::regclass;
drop table test;
因此,由于某种原因,添加具有默认值的列似乎会更改关系的文件节点。关于 relfilenode
和其他属性的更多详细信息,也值得阅读 PostgreSQL docs on pg_class
。
不要在名字文本上加入目录,你只需要数字id就可以加入(目录中的名字是区分大小写的,这只会让你感到困惑) .另外:您不需要 pg_tables 目录;这只是 pg_class
上的一个视图WRT 消失的目录条目:您是否提交了您的变更 table DDL? DDL 需要对目录执行一些技巧以对其他会话隐藏新版本。
select c.relname, i.indkey,i.indexrelid , i.indrelid
from pg_catalog.pg_index i
inner join pg_catalog.pg_class c
on i.indrelid=c.relfilenode
where c.relname='target';