×
技术社区 >  技术博客 >  OceanBase 解惑 | NOT NULL 时间字段用 IS NULL 却查出数据?

OceanBase 解惑 | NOT NULL 时间字段用 IS NULL 却查出数据?

问题现象

在 OceanBase MySQL 模式下,业务表中某个DATETIME NOT NULL字段保存了零时间值0000-00-00 00:00:00。执行IS NULL条件查询时,发现该行会被查出来,表现上像是被当成了 NULL。
示例:

CREATE TABLE t1date(
  c1 INT,
  c2 DATETIME NOT NULL
);

INSERT IGNORE INTO t1date VALUES (1, '0000-00-00 00:00:00');
INSERT IGNORE INTO t1date VALUES (2, '2025-11-01 12:20:00');
SELECT * FROM t1date WHERE c2 IS NULL;

查询结果:

1   0000-00-00 00:00:00

第 1 行会命中,第 2 行不会命中。

影响范围

该行为主要出现在以下条件同时满足时:

✅租户为 MySQL 模式

✅列类型为 DATE / DATETIME

✅列属性为 NOT NULL

✅SQL 条件中使用了 WHERE col IS NULL

原因分析

这不是存储层把 0000-00-00 00:00:00 真正存成了 NULL,而是 SQL 解析阶段做了兼容性改写。

在 OB 的 DML Resolver 中,对于 NOT NULL 的时间类型列,如果 SQL 中写的是:col IS NULL
会被改写为类似:

col IS NULL OR col = '0000-00-00 00:00:00'

因此,虽然字段值本身不是 NULL,但在 WHERE ... IS NULL 的过滤逻辑中,零时间会被一并匹配出来。

关键说明

这个行为主要是谓词过滤场景下的改写,不代表零时间在系统内部被当成真正的 NULL 值。

也就是说:

● 0000-00-00 00:00:00 仍然是一个特殊的零时间值

● 但在 WHERE c2 IS NULL 这类条件里,OB 为兼容性会把它纳入结果集

为什么会出现零时间

常见原因包括:

  1. 使用了 INSERT IGNORE
  2. SQL Mode 未严格禁止零日期/零时间
  3. 非法或不完整时间在告警模式下被转换成零时间

例如:

INSERT IGNORE INTO t1date VALUES (1, '0000-00-00 00:00:00');

该语句不会报错,而是插入零时间。

结论

在 OceanBase MySQL 模式下,DATETIME NOT NULL 字段上的IS NULL谓词存在兼容性改写逻辑。

对于零时间值 0000-00-00 00:00:00,OB 会在条件过滤阶段将其视作 IS NULL 的匹配对象之一,因此出现零时间被 IS NULL 查询命中的现象。属于 SQL 解析层的兼容行为,并非存储层将零时间物理转换为 NULL。

精选推荐