【OceanBase 诊断调优】—— 无主键表的 ROWID 和隐藏主键 __pk_increment

适用版本:V2.1.x、V2.2.x、V3.1.x、V3.2.x、V4.x

无主键表是指用户在创建时没有指定主键的表,此时 OceanBase MySQL 模式和 Oracle 模式的数据库均会采用一个自增的列作为隐藏主键。隐藏主键的数据类型为 BIGINT,最大值为 2^64 。

对于 OceanBase Oracle 模式的数据库,跟原生 Oracle 对齐,每个表都有一个名为 ROWID 的伪列。OceanBase Oracle 数据库使用 ROWID 数据类型来存储数据库中每一行的地址。本文主要介绍 OceanBase 各个版本中这两个对象的特点、二者之间的关系,以及如何使用 select 语句来查询 ROWID 和隐藏主键。

详细说明

ROWID

在 OceanBase Oracle 数据库中,每个表都有一个名为 ROWID 的伪列。 伪列的行为类似一个表的普通列,但实际上并没有存储在表中。可以通过伪列执行 SELECT 操作,但不能对它们的值执行 INSERT、UPDATE、DELETE 操作。伪列也类似于没有参数的 SQL 函数。不带参数的函数通常为结果集中的每一行返回相同的值,而伪列通常为每一行返回不同的值。 ROWID 伪列的值是每行数据的 Key(对于有主键表是 Primary Key,对于无主键表是系统自动生成的序列),通过 Base64 编码转换而成。可以通过使用保留字 ROWID 作为列名的 SQL 来访问每一行的 ROWID。 在 OceanBase 数据库 V2.x/V3.x 版本中无主键表的 ROWID 会编码分区键的信息(OceanBase 数据库 V2.x/V3.x 版本中无主键表的 ROWID 是按照 自增列+分区键 编码转换的),长度不固定。如果分区键字段内容很长的话,ROWID 就会很长;而在 OceanBase 数据库 V4.x 版本中无主键表的 ROWID 为固定长度 16 字节,彻底解决了 ROWID 超长问题。

隐藏主键

OceanBase 数据库的无主键表采用自增列作为隐藏主键。无主键表利用了自增列的多分区全局唯一的原则,以此保证无主键表隐藏键的唯一性。

  • ROWID 长度调整前(OceanBase 数据库 V2.x/V3.x 版本)。

    无主键表隐藏主键的格式如下:

    复制代码
    create table t1(c1 int); -- 隐藏主键为__pk_increment
    
    create table t1(c1 int, c2 int) partition by hash(c2); -- 隐藏主键为(c2, __pk_increment)

可以看出无主键表的隐藏主键里面会包含分区键,这使得 OceanBase 的无主键表 ROWID 的长度是不固定的,最长可能会到 16K 。

  • ROWID长度调整后(OceanBase 数据库 V4.x 版本)。

    无主键表的隐藏主键格式变为如下:

    复制代码
    create table t1(c1 int); -- 隐藏主键为__pk_increment
    
    create table t1(c1 int, c2 int) partition by hash(c2); -- 隐藏主键为(__pk_increment)

    可以看出在 OceanBase 数据库 V4.x 版本中无主键分区表自动创建的隐藏主键不再包含分区键了。

二者关系及如何查看

OceanBase 数据库 Oracle 模式中的 ROWID 是基于 __pk_increment 和其它信息(OceanBase 数据库 V2.x/3.x 版本中为分区键,V4.x 版本中为 tablet id)一起编码产生的一个伪列,但不等同于 __pk_increment

示例如下:

  1. 查看表 t2 的表结构。

    复制代码
    obclient [SYS]> desc t2;

    输出结果如下:

    复制代码
    +-------+---------------+------+------+---------+-------+
    | FIELD | TYPE          | NULL | KEY  | DEFAULT | EXTRA |
    +-------+---------------+------+------+---------+-------+
    | ID    | NUMBER(38)    | YES  | UNI  | NULL    | NULL  |
    | NAME  | VARCHAR2(100) | YES  | NULL | NULL    | NULL  |
    +-------+---------------+------+------+---------+-------+
    2 rows in set (0.004 sec)
  2. 查询表 t2 的完整结构。

    复制代码
    obclient [SYS]> show create table t2;

    输出结果如下:

    复制代码
    +-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | TABLE | CREATE TABLE                                                                                                                                                                                           |
    +-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | T2    | CREATE TABLE "T2" (
    "ID" NUMBER(*,0),
    "NAME" VARCHAR2(100),
    UNIQUE ("ID")
    ) COMPRESS FOR ARCHIVE REPLICA_NUM = 1 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0 |
    +-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    1 row in set (0.005 sec)
  3. 查询表 t2 的内容。

    复制代码
    obclient [SYS]> select * from t2;

    输出结果如下:

    复制代码
    +------+------+
    | ID   | NAME |
    +------+------+
    |    1 | a    |
    |    2 | b    |
    | NULL | c    |
    +------+------+
    3 rows in set (0.001 sec)
  4. 在查询表 t2 语句中添加 hint 打开隐藏列可见,获取 __pk_increment 值。

    复制代码
    obclient [SYS]> select /*+ opt_param('hidden_column_visible','true') */ id,"__pk_increment" from t2;   -- OceanBase 数据库 V4.x 版本中 Oracle 模式和 MySQL 模式均适用

    输出结果如下:

    复制代码
    +------+----------------+
    | ID   | __pk_increment |
    +------+----------------+
    |    1 |              1 |
    |    2 |              4 |
    | NULL |              6 |
    +------+----------------+
    3 rows in set (0.001 sec)
  5. 在查询表 t1 语句中添加 hint 打开隐藏列可见,获取 __pk_increment 值。

    复制代码
    MySQL [test]> select /*+ opt_param('hidden_column_visible','true') */ id,`__pk_increment` from t1;
    
    +------+----------------+
    | id   | __pk_increment |
    +------+----------------+
    |    1 |              1 |
    |    2 |              2 |
    | NULL |              3 |
    +------+----------------+
    3 rows in set (0.001 sec)
    
    MySQL [test]> select /*+ opt_param('hidden_column_visible','true') */ id,__pk_increment from t1;
    +------+----------------+
    | id   | __pk_increment |
    +------+----------------+
    |    1 |              1 |
    |    2 |              2 |
    | NULL |              3 |
    +------+----------------+
    3 rows in set (0.003 sec)
  6. 在查询表 t2 语句中添加 hint 打开隐藏列可见,获取 __pk_incrementROWID 值。

    复制代码
    obclient [SYS]> select /*+ opt_param('hidden_column_visible','true') */ id,"__pk_increment",rowid from t2;

    输出结果如下:

    复制代码
    +------+----------------+------------------+
    | ID   | __pk_increment | ROWID            |
    +------+----------------+------------------+
    |    1 |              1 | gAADDVQAAAAAAQ== |
    |    2 |              4 | gAADDVQAAAAABA== |
    | NULL |              6 | gAADDVQAAAAABg== |
    +------+----------------+------------------+
    3 rows in set (0.003 sec)
  7. 在查询表 t2 语句中添加 hint 打开隐藏列可见,获取 __pk_increment 值和 ROWID 的长度值。

    复制代码
    obclient [SYS]> select /*+ opt_param('hidden_column_visible','true') */ id,"__pk_increment",length(rowid) from t2;

    输出结果如下:

    复制代码
    +------+----------------+---------------+
    | ID   | __pk_increment | LENGTH(ROWID) |
    +------+----------------+---------------+
    |    1 |              1 |            16 |
    |    2 |              4 |            16 |
    | NULL |              6 |            16 |
    +------+----------------+---------------+
    3 rows in set (0.001 sec)

总结

  • hidden_column_visible 的 sql hint 是在 OceanBase 数据库 V4.x 版本中才引入的,而在 V3.x 版本中无此 hint,因此在 OceanBase 数据库 V3.x 版本中 Oracle 模式下目前暂不支持直接查询隐藏主键 __pk_increment

  • 对于 OceanBase 数据库 V2.x/V3.x/V4.x MySQL 模式租户,还可以使用内部用户 __oceanbase_inner_drc_user 去查询隐藏主键,具体参见:OceanBase 数据库中如何访问隐藏自增列的值

相关推荐
ActionTech9 天前
ChatDBA VS DeepSeek:快速诊断 OceanBase 集群新租户数据同步异常
oceanbase·deepseek·chatdba·爱可生
码农老起9 天前
从Oracle到OceanBase数据库迁移:全方位技术解析
数据库·oracle·oceanbase
OceanBase数据库官方博客10 天前
数据文件误删除,OceanBase中如何重建受影响的节点
oceanbase·分布式数据库·运维管理·实践经验
码农老起13 天前
OceanBase数据库基于脚本的分布式存储层性能深度优化
数据库·分布式·oceanbase
码农老起13 天前
万亿级数据量的OceanBase应用从JVM到协议栈立体化改造实现性能调优
jvm·oceanbase
OceanBase数据库官方博客15 天前
OceanBase 读写分离最佳实践
oceanbase·分布式数据库·读写分离·最佳实践
OceanBase数据库官方博客17 天前
网易云信架构升级实践,故障恢复时间缩至8秒
oceanbase·分布式数据库·架构选型·布道师计划
OceanBase数据库官方博客19 天前
自然语言秒转SQL—— 免费体验 OB Cloud Text2SQL 数据查询
数据库·sql·ai·oceanbase·分布式数据库·向量·text2sql
OceanBase数据库官方博客1 个月前
关于OceanBase与CDH适配的经验分享
oceanbase·分布式数据库·cdh
OceanBase数据库官方博客1 个月前
石基大商:OceanBase + Flink CDC,搭建连锁零售系统数据湖
flink·oceanbase·分布式数据库·实时数仓·零售