前言

今天有个业务的妹子问我“在吗?”
我说什么事?
她说:“我们Oracle的数据库里有rowid,想问问在PostgreSQL中怎么迁移过去使用。”
我说:“rowid没有,只有ctid。”
她又问:“ctid是什么东东?”
我说:“Oracle的rowid是什么,在PostgreSQL中ctid就是什么?如果你的表上或者是程序上有Oracle的rowid,那肯定是不支持的。需要改造成ctid。”
CTID 代表了什么?
在Oracle中,每一行数据都会有一个唯一标识符,简称为rowid。而在PostgreSQL里面,我们可以使用ctid,表中的每一行数据都有唯一的ctid,它表示元组的位置。
我们首先来创建一个表。
create table t(id serial);
insert into t values(generate_series(1,10));
postgres=# select ctid,id from t;
ctid | id
--------+----
(0,1) | 1
(0,2) | 2
(0,3) | 3
(0,4) | 4
(0,5) | 5
(0,6) | 6
(0,7) | 7
(0,8) | 8
(0,9) | 9
(0,10) | 10
(10 rows)复制
这里可以看到ctid表示的值。对于(0,1),第一个数据0代表page号,第二个数字代表了元组编号。ctid的值都是顺序的。如果我们只想显示page编号或者元组编号,我们该怎么写呢?
postgres=# SELECT (ctid::text::point)[0]::bigint AS page_number,
(ctid::text::point)[1]::bigint AS tuple_number FROM t;
page_number | tuple_number
-------------+--------------
0 | 1
0 | 2
0 | 3
0 | 4
0 | 5
0 | 6
0 | 7
0 | 8
0 | 9
0 | 10
(10 rows)复制
MVCC下的CTID
我们知道PostgreSQL实现MVCC的机制和Oracle、MySQL是不一样的,当更新一个值的时候,我们讲观察到更新的那个值将拥有新的CTID,它不会使用就值所使用的CTID。
postgres=# update t set id=11 where id=5;
UPDATE 1
postgres=# SELECT (ctid::text::point)[0]::bigint AS page_number,
(ctid::text::point)[1]::bigint AS tuple_number,
id from t;
page_number | tuple_number | id
-------------+--------------+----
0 | 1 | 1
0 | 2 | 2
0 | 3 | 3
0 | 4 | 4
0 | 6 | 6
0 | 7 | 7
0 | 8 | 8
0 | 9 | 9
0 | 10 | 10
0 | 11 | 11复制
这里可以看到当我把id=5的改成id=11,这一行的ctid也变成了(0,11)。而(0,5)这个ctid暂时看不见了。而当我们执行vacumm full之后,你会发现ctid被重置了,重置是顺序分配的。
postgres=# vacuum full t;
VACUUM
postgres=# SELECT (ctid::text::point)[0]::bigint AS page_number,
(ctid::text::point)[1]::bigint AS tuple_number,
id from t;
page_number | tuple_number | id
-------------+--------------+----
0 | 1 | 1
0 | 2 | 2
0 | 3 | 3
0 | 4 | 4
0 | 5 | 6
0 | 6 | 7
0 | 7 | 8
0 | 8 | 9
0 | 9 | 10
0 | 10 | 11复制
之前的(0,6)对应的是6,现在(0,5)对应了6。
理论上在vacumm analyze之后,死元组被清理掉之后,应该可以重用。但是我在PostgreSQL 13这个版本遇到的情况是仍然无法使用。这让我有点诧异。
postgres=# update t set id =12 where id=11;
UPDATE 1
postgres=# SELECT (ctid::text::point)[0]::bigint AS page_number,
(ctid::text::point)[1]::bigint AS tuple_number,
id from t;
page_number | tuple_number | id
-------------+--------------+----
0 | 1 | 1
0 | 2 | 2
0 | 3 | 3
0 | 4 | 4
0 | 5 | 6
0 | 6 | 7
0 | 7 | 8
0 | 8 | 9
0 | 9 | 10
0 | 11 | 12
(10 rows)
postgres=# vacuum analyze t;
VACUUM
postgres=# SELECT (ctid::text::point)[0]::bigint AS page_number,
(ctid::text::point)[1]::bigint AS tuple_number,
id from t;
page_number | tuple_number | id
-------------+--------------+----
0 | 1 | 1
0 | 2 | 2
0 | 3 | 3
0 | 4 | 4
0 | 5 | 6
0 | 6 | 7
0 | 7 | 8
0 | 8 | 9
0 | 9 | 10
0 | 11 | 12
(10 rows)
postgres=# insert into t values(11);
INSERT 0 1
postgres=# SELECT (ctid::text::point)[0]::bigint AS page_number,
(ctid::text::point)[1]::bigint AS tuple_number,
id from t;
page_number | tuple_number | id
-------------+--------------+----
0 | 1 | 1
0 | 2 | 2
0 | 3 | 3
0 | 4 | 4
0 | 5 | 6
0 | 6 | 7
0 | 7 | 8
0 | 8 | 9
0 | 9 | 10
0 | 11 | 12
0 | 12 | 11
(11 rows)复制
后记
今天学习了CTID的皮毛知识,最近在外地出差真的很忙啊,连回复开发妹子的时间都没有了。
文章转载自励志成为PostgreSQL大神,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
相关阅读
外国CTO也感兴趣的开源数据库项目——openHalo
小满未满、
1996次阅读
2025-04-21 16:58:09
【纯干货】Oracle 19C RU 19.27 发布,如何快速升级和安装?
Lucifer三思而后行
790次阅读
2025-04-18 14:18:38
Oracle RAC 一键安装翻车?手把手教你如何排错!
Lucifer三思而后行
664次阅读
2025-04-15 17:24:06
Oracle数据库一键巡检并生成HTML结果,免费脚本速来下载!
陈举超
592次阅读
2025-04-20 10:07:02
【ORACLE】你以为的真的是你以为的么?--ORA-38104: Columns referenced in the ON Clause cannot be updated
DarkAthena
548次阅读
2025-04-22 00:13:51
【活动】分享你的压箱底干货文档,三篇解锁进阶奖励!
墨天轮编辑部
534次阅读
2025-04-17 17:02:24
【ORACLE】记录一些ORACLE的merge into语句的BUG
DarkAthena
510次阅读
2025-04-22 00:20:37
一页概览:Oracle GoldenGate
甲骨文云技术
498次阅读
2025-04-30 12:17:56
火焰图--分析复杂SQL执行计划的利器
听见风的声音
471次阅读
2025-04-17 09:30:30
OR+DBLINK的关联SQL优化思路
布衣
383次阅读
2025-05-05 19:28:36