range分区的null路由问题

官方文档有这样的描述:


意思是分区间如果是null的情况,会把此条记录写入 values less than (MAXVALUE)) 这个分区吗?

实际案例:

obclient [test]> show create table parttb_range_2 \G
*************************** 1. row ***************************
       Table: parttb_range_2
Create Table: CREATE TABLE `parttb_range_2` (
  `id` int(11) DEFAULT NULL,
  `gmt_create` datetime DEFAULT NULL,
  `info` varchar(20) DEFAULT NULL
) DEFAULT CHARSET = utf8mb4 ROW_FORMAT = DYNAMIC COMPRESSION = 'zstd_1.3.8' REPLICA_NUM = 3 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0
 partition by range columns(gmt_create)
(partition `p0` values less than ('2025-01-01 00:00:00'),
partition `p1` values less than (MAXVALUE))
1 row in set (0.004 sec)

obclient [test]> select * from parttb_range_2;
+------+---------------------+------+
| id   | gmt_create          | info |
+------+---------------------+------+
|    2 | 2024-12-01 00:00:00 | 2    |
|    3 | NULL                | 3    |
|    1 | 2025-01-01 00:00:00 | 1    |
+------+---------------------+------+
3 rows in set (0.053 sec)

explain route select * from parttb_range_2 where gmt_create is null;

实际上好像路由到P0分区了

1 个赞

@论坛小助手

根据文档库中的信息,RANGE 分区在处理 NULL 值时的行为如下:

  1. 官方文档描述
    在 OceanBase 数据库中,默认采用 NULL first 的比较模式。这意味着在排序或分区时,NULL 值会被视为小于任何非 NULL 值。因此,在 RANGE 分区表中,NULL 值会路由到第一个分区(即定义为 VALUES LESS THAN (某个值) 的分区)。

  2. 实际案例分析
    根据您提供的表结构和查询结果:

    CREATE TABLE `parttb_range_2` (
      `id` int(11) DEFAULT NULL,
      `gmt_create` datetime DEFAULT NULL,
      `info` varchar(20) DEFAULT NULL
    ) DEFAULT CHARSET = utf8mb4 ROW_FORMAT = DYNAMIC COMPRESSION = 'zstd_1.3.8' REPLICA_NUM = 3 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0
    partition by range columns(gmt_create)
    (partition `p0` values less than ('2025-01-01 00:00:00'),
     partition `p1` values less than (MAXVALUE));
    
    • 表的分区规则是基于 gmt_create 列的 RANGE COLUMNS 分区。
    • 第一个分区 p0 定义为 VALUES LESS THAN ('2025-01-01 00:00:00')
    • 第二个分区 p1 定义为 VALUES LESS THAN (MAXVALUE)

    当插入一条记录的 gmt_create 列为 NULL 时,根据 NULL first 的比较规则,NULL 值会被视为小于 '2025-01-01 00:00:00',因此该记录被路由到 p0 分区。

  3. 解释您的疑问
    您提到的“是否会把此条记录写入 VALUES LESS THAN (MAXVALUE) 这个分区”实际上不会发生。因为 NULL 值在 RANGE 分区中被视为小于任何具体的值(如 '2025-01-01 00:00:00'),所以它会被路由到第一个匹配的分区 p0,而不是 p1

  4. 验证查询计划
    您通过 EXPLAIN ROUTE 查询发现记录确实路由到了 p0 分区,这与上述逻辑一致。

总结

根据文档库中的信息以及实际案例分析,RANGE 分区表中 NULL 值会被路由到第一个匹配的分区(即 VALUES LESS THAN (某个值) 的分区)。在您的例子中,NULL 值被正确路由到了 p0 分区,而不是 p1 分区。

如果您希望避免这种行为,可以在设计表时明确排除 NULL 值,或者使用 NVL()IFNULL() 函数将 NULL 转换为特定值。例如:

CREATE TABLE `parttb_range_2` (
  `id` int(11) DEFAULT NULL,
  `gmt_create` datetime DEFAULT NULL,
  `info` varchar(20) DEFAULT NULL
) DEFAULT CHARSET = utf8mb4 ROW_FORMAT = DYNAMIC COMPRESSION = 'zstd_1.3.8' REPLICA_NUM = 3 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0
partition by range columns(NVL(gmt_create, '9999-12-31 23:59:59'))
(partition `p0` values less than ('2025-01-01 00:00:00'),
 partition `p1` values less than (MAXVALUE));

这样可以确保 NULL 值被路由到指定的分区。

具体信息可参考以下文档:

  1. 向量检索核心功能
  2. 0001 ~ 3999
  3. 使用 OceanBase 数据库分区表进行水平拆分
  4. SQL FAQ
  5. information_schema.role_column_grants
  6. 5000 ~ 5999
  7. OceanBase 术语
  8. 查询中使用 NULL 相关函数
1 个赞

官网并未说存放在哪个分区,根据自己测试的为基准
你看的是oracle模式的,建议咨询商业技术支持

1 个赞