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

发布于:2024-11-29 ⋅ 阅读:(25) ⋅ 点赞:(0)

适用版本: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_increment 和 ROWID 值。

    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 数据库中如何访问隐藏自增列的值


网站公告

今日签到

点亮在社区的每一天
去签到