HGDB兼容性之oracle的rowid

文章目录

文档用途

oracle中的rowid伪列,有很重要的应用场景,但是HGDB中没有该伪列,本文档介绍HGDB如何兼容实现oracle中的rowid功能。

详细信息

oracle中的rowid

什么是rowid?

rowid是数据的详细物理地址,通过rowid,oracle可以快速的定位某行具体数据的位置。

创建测试表

sql 复制代码
 create table test(id number,name varchar2(10));

插入测试数据

sql 复制代码
  insert into test values(0,'orcl');

     insert into test valurs(1,'orcl');

     insert into test values(2,'orcl');

     insert into test values(3,'orcl');

查看表内容

sql 复制代码
select rowid,id,name from test;

 ROWID                      ID NAME

 ------------------ ---------- ---------------

 AAAV5DAAOAAAACWAAA          0 orcl

 AAAV5DAAOAAAACWAAB          1 orcl

 AAAV5DAAOAAAACWAAC          3 orcl

 AAAV5DAAOAAAACWAAD          2 orcl

rowid的结构

我们从rowid伪列里select出来的rowid是基于base64编码,一共有18位,分为4部分:

形如OOOOOOFFFBBBBBBRRR,其中:

  • 前6位(OOOOOO)为数据对象ID,一张表、一个索引都是一个数据对象,oracle都会分配给它们一个唯一的数据对象ID。
  • 紧跟的3位(FFF)为相对的文件ID,我们知道表空间是由不同的文件组成,对象存储在某个文件里,每个文件会对应一个ID号。
  • 再接着的6位(BBBBBB)为块ID,文件是由块组成的,每个块也有一个唯一的ID号。
  • 最后3位(RRR)为行ID,每个块可以划分为行,每个行也有一个ID号。

rowid的应用场景

  • 去重
sql 复制代码
   delete tt a

   where a.rowid <( select max( b.rowid )

   from tt b

   where a.employee_id = b.employee_id

   and a.first_name = b.first_name

   and a.last_name = b.last_name

   and a.title = b.title

   and a.salary = b.salary );

rowid是行的"身份证号",哪怕两行中的数据完全相同,其rowid值也是不一样的(正如像个同名同姓的人,身份证号码不一样)。为什么要用到MAX这个函数?这就涉及到ROWID的性质了,ROWID是有具体值的,是可以比较大小的,先找出表中重复的行的ROWID的最大值,然后<>表示只保留重复行中ROWID最大值的那一行,其余的那几行全部删除,所以这个地方也可以使用MIN,即只保留ROWID最小的那一行,即可实现去重的作用。

  • 作为主键,用于查询
sql 复制代码
   select * from tt where rowid = 'XXXXX';

有些应用会将rowid当作数据主键进行查询,可以作为主键的原因是rowid具有唯一性,甚至是全库唯一性,但是他跟我们自建主键的区别是,在数据修改或者导入导出等操作时,rowid可能会自动变化。所以用rowid作为主键时适合用于对其值不敏感,仅作为区分不同数据的情况下使用。也正因为这种性质接下来的用法"作为外键用于引用"也是完全错误的。另外oracle中的索引也是利用了rowid唯一性。

  • 作为外键用于引用
sql 复制代码
   select * from tb_a left join tb_b on tb_b.tbarowid=tb_a.rowid where xxxxx;

虽然这种用法是完全错误的,但是假如迁移过程中碰到这种情况,也只能用最笨且最有效的办法,新建字段,将rowid值更新到字段中并且修改外键映射。当表比较多时,工作量非常大。

HGDB兼容性

  • ctid

ctid是HGDB中行版本在其表中的物理位置。尽管ctid可以被用来非常快速地定位行版本,但是一个行的ctid会在被更新或者被VACUUM FULL移动时改变。因此,ctid不能作为一个长期行标识符。OID或者最好一个用户定义的序列号才应该被用来标识逻辑行,它也是由系统自动生成,不过结构和rowid不同,ctid的结构是(blockid,itemid)。

sql 复制代码
    select ctid,* from t2;

    ctid  | id |  name

    -------+----+--------

    (0,1) |  1 | apple

    (0,2) |  1 | apple

    (0,3) |  1 | apple

    (0,4) |  2 | orange

    (0,5) |  2 | orange

    (0,6) |  2 | orange

    (0,7) |  3 | banana

    (0,8) |  3 | banana

    --利用ctid去重    

    delete from t2 where ctid not in (select min(ctid) from t2 group by id);

oid


   testdb=> create sequence test_seq;  --创建序列发生器-sequence,当然大纲中还有很多其他参数     可选。

   CREATE SEQUENCE

   testdb=> create table test_db(id bigint default nextval('test_seq') not null,name varchar);     -- 字段设置默认值

   CREATE TABLE

   testdb=> create unique index test_db_idx_1 on test_db(id); --创建唯一索引以增强序列的唯一性

   CREATE INDEX

   testdb=> insert into test_db(name) values('Tom'),('Jack'),('Jone'); --插入数据测试

   INSERT 0 3

   testdb=> select * from test_db;

   id | name

   ----+------

   1 | Tom

   2 | Jack

   3 | Jone

   (3 rows)

这样就创建好了一个自增的可以保证表唯一的主键,当然在库中的其他表也可以使用这一个序列生成器从而实现数据的全库唯一性,序列是基于bigint算法的,因此他的范围不能超过一个八字节(范围大于oid的4字节)整数的范围-9223372036854775808到9223372036854775807。

  • serial

serial是一种数据类型。

sql 复制代码
   testdb=> create table test_t3(id serial not null,name varchar);

    CREATE TABLE

    testdb=> \ds

     List of relations

    Schema |      Name      |   Type   |  Owner   

    --------+----------------+----------+----------

    public | test_seq       | sequence | testuser

    public | test_t2_id_seq | sequence | testuser

    public | test_t3_id_seq | sequence | testuser

    public | test_t_id_seq  | sequence | testuser

    (4 rows)

创建一个serial列时,会自动创建一个sequence,可见他的实现机理跟sequence一样的,当然对应sequence的int类型,serial包含serial,serial2,serial8 3种可选类型。

  • identity

    创建identity自增列,类似与mysql的AUTO_INCREMENT,方法:

sql 复制代码
   testdb=> create table test_t(id int generated always as identity not null,name varchar);

    --always 

    CREATE TABLE    

    testdb=> create table test_t2(id int generated by default as identity not null,name varchar);  --by default

    CREATE TABLE 

    --ALWAYS,表示优先使用系统列生成的自增值。

    --BY DEFAULT,表示优先使用用户输入的值。
相关推荐
蓝创工坊Blue Foundry2 分钟前
图片文字提取到 Excel:批量任务如何先定义要交付的字段
运维·服务器·开发语言·数据库·自动化·ocr·excel
麦聪聊数据23 分钟前
企业数据市场建设(三):API 化服务封装,让数据开箱即用、避免重复开发
数据库
脱胎换骨-军哥27 分钟前
C++数据库存储引擎内核开发:B+树索引与MVCC并发控制的完整实现
数据库·c++·b树
麦聪聊数据34 分钟前
企业数据市场建设(四):流程闭环与价值运营,让数据市场真正转起来
运维·数据库
正儿八经的少年41 分钟前
redis 的大 key 和热 key 详解
数据库·redis·缓存
AI砖家1 小时前
多智能体系统实战:架构设计、数据库表设计与 Skill 体系
数据库·多智能体·skill·agent架构设计·agengt
夜雪一千1 小时前
MySQL查询条件的顺序是否影响查询效率
数据库·mysql
X-⃢_⃢-X1 小时前
十、Redis之布隆过滤器
数据库·redis·缓存
Nturmoils2 小时前
订单号查出了三笔,我以为是数据脏了,其实是自己写错了
数据库
ZKNOW甄知科技2 小时前
燕千云深度集成飞书:以AI之力,开启无感IT运维体验
大数据·运维·网络·数据库·人工智能·低代码·集成学习