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 个赞