联系我们
18591797788
hubin@rlctech.com
北京市海淀区中关村南大街乙12号院天作国际B座1708室
18681942657
lvyuan@rlctech.com
上海市浦东新区商城路660号乐凯大厦26c-1
18049488781
xieyi@rlctech.com
广州市越秀区东风东路华宫大厦808号1608房
029-81109312
service@rlctech.com
西安市高新区天谷七路996号西安国家数字出版基地C座501
OceanBase 一套内核兼容 MySQL 和 Oracle 两种租户模式,但对NULL、''(空串)的底层处理逻辑天差地别。本文基于 OB V4.2.1.7 实测验证,把两种模式下存储、查询、COUNT 统计、唯一索引四大核心场景讲透,看完直接规避线上故障。
【NULL 与空字符串】一句话核心总结:
MySQL 模式:空串 '' 是普通字符串,与 NULL 完全不同;
Oracle 模式:空串 '' 被视为 NULL,两者等价;
| 操作场景 | OB Oracle 模式 | OB MySQL 模式 |
|---|---|---|
插入空串 '' |
自动转为 NULL |
保持为空串 '' |
空串是否为 NULL |
是 | 否 |
NULL 与空串比较 |
不相等 | 不相等 |
COUNT(column) |
不统计 NULL,不统计空串 |
不统计 NULL,统计空串 |
唯一索引中多个 NULL |
不冲突(允许) | 不冲突(允许) |
| 唯一索引中多个空串 | 不冲突(因为被转为 NULL) |
冲突(不允许) |
创建 test_mysql_260527 表并插入 3 条数据,分别是:空字符串,NULL,正常值;
mysql -h192.168.xxx.xxx -P2883 -uroot@mysql_251126#ob_4255_251126 -p'xxx' -A -Dtest
CREATE TABLE test_mysql_260527 ( id INT, col_1 VARCHAR(50)); -- 创建测试表
INSERT INTO test_mysql_260527 VALUES (1, ''), (2, NULL), (3, 'abc'); -- 插入测试数据,分别是:空字符串,NULL,正常值;
-- DROP TABLE test_mysql_260527; -- 清理测试表
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 6572857
Server version: 5.6.25 OceanBase 4.2.1.7 (r107010022024060601-fe709b4735794f5e577d5b14f91d9183a12f101e) (Built Jun 6 2024 01:33:55)
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MySQL [test]> CREATE TABLE test_mysql_260527 ( id INT, col_1 VARCHAR(50)); -- 创建测试表
Query OK, 0 rows affected (0.39 sec)
MySQL [test]> INSERT INTO test_mysql_260527 VALUES (1, ''), (2, NULL), (3, 'abc'); -- 插入测试数据,分别是:空字符串,NULL,正常值;
Query OK, 3 rows affected (0.08 sec)
Records: 3 Duplicates: 0 Warnings: 0
在 V 4.2.1.7 版本的 MySQL 租户模式中,验证【null 值】和【''(即空值,空字符串)】的区别;验证结果:在 OB MySQL 模式中,以上 2 者是不等价的;
-- 【sql-01】查询空字符串(应返回 id=1 的行)
SELECT * FROM test_mysql_260527 WHERE col_1 = '';
-- 【sql-02】查询 NULL(应返回 id=2 的行)
SELECT * FROM test_mysql_260527 WHERE col_1 IS NULL;
-- 【sql-03】= NULL 语法不会返回任何结果(错误用法)
SELECT * FROM test_mysql_260527 WHERE col_1 = NULL; -- 返回空集
MySQL [test]> SELECT * FROM test_mysql_260527 WHERE col_1 = '';
+------+-------+
| id | col_1 |
+------+-------+
| 1 | |
+------+-------+
1 row in set (0.01 sec)
MySQL [test]> SELECT * FROM test_mysql_260527 WHERE col_1 IS NULL;
+------+-------+
| id | col_1 |
+------+-------+
| 2 | NULL |
+------+-------+
1 row in set (0.01 sec)
MySQL [test]> SELECT * FROM test_mysql_260527 WHERE col_1 = NULL; -- 返回空集
Empty set (0.00 sec)
在 OB MySQL 模式中:count(col_1) 函数会忽略 NULL 值,所以预期结果为 2;
-- 【sql-04】验证 count 函数对 null 和 空字符串的处理(预期结果为:2)
SELECT count(col_1) FROM test_mysql_260527;
MySQL [test]> SELECT count(col_1) FROM test_mysql_260527;
+--------------+
| count(col_1) |
+--------------+
| 2 |
+--------------+
1 row in set (0.01 sec)
在 OB MySQL 模式中:唯一索引是允许 NULL 值重复的;空字符串是不允许重复的;所以第 1 条 insert 语句成功,第 2 条 insert 语句失败;
-- 【sql-05】验证对唯一索引的影响:
CREATE UNIQUE INDEX idx_unique_col_1 ON test_mysql_260527 (col_1); -- 在 col_1 字段上创建唯一索引
INSERT INTO test_mysql_260527 VALUES (4, NULL);
INSERT INTO test_mysql_260527 VALUES (5, '');
MySQL [test]> CREATE UNIQUE INDEX idx_unique_col_1 ON test_mysql_260527 (col_1);
Query OK, 0 rows affected (0.81 sec)
MySQL [test]> INSERT INTO test_mysql_260527 VALUES (4, NULL);
Query OK, 1 row affected (0.01 sec)
MySQL [test]> INSERT INTO test_mysql_260527 VALUES (5, '');
ERROR 1062 (23000): Duplicate entry '' for key 'idx_unique_col_1'
创建 test_oracle_260527 表并插入 3 条数据,分别是:空字符串,NULL,正常值;
obclient -h192.168.xxx.xxx -P2883 -uSYS@oracle_250917#ob_4255_251126 -p'xxx' -A
CREATE TABLE test_oracle_260527 ( id INT, col_1 VARCHAR(50)); -- 创建测试表
INSERT INTO test_oracle_260527 VALUES (1, ''), (2, NULL), (3, 'abc'); -- 插入测试数据,分别是:空字符串,NULL,正常值;
-- DROP TABLE test_oracle_260527; -- 清理测试表
Welcome to the OceanBase. Commands end with ; or \g.
Your OceanBase connection id is 6572969
Server version: OceanBase 4.2.1.7 (r107010022024060601-fe709b4735794f5e577d5b14f91d9183a12f101e) (Built Jun 6 2024 01:33:55)
Copyright (c) 2000, 2018, OceanBase and/or its affiliates. All rights reserved.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
obclient(SYS@oracle_250917)[SYS]> CREATE TABLE test_oracle_260527 ( id INT, col_1 VARCHAR(50)); -- 创建测试表
Query OK, 0 rows affected (0.369 sec)
obclient(SYS@oracle_250917)[SYS]> INSERT INTO test_oracle_260527 VALUES (1, ''), (2, NULL), (3, 'abc'); -- 插入测试数据,分别是:空字符串,NULL,正常值;
Query OK, 3 rows affected (0.054 sec)
Records: 3 Duplicates: 0 Warnings: 0
使用 insert into 语句插入【''(空字符串)】时,OB 会自动将其转换成 NULL 值并存储,但是在查询时(where 条件中),若使用【''(空字符串)】则不能查出数据,必须使用 IS NULL 或 IS NOT NULL;
-- 【sql-01】查询空字符串(返回空集)
SELECT * FROM test_oracle_260527 WHERE col_1 = '';
-- 【sql-02】查询 NULL(应返回 id = 1/2 的行)
SELECT * FROM test_oracle_260527 WHERE col_1 IS NULL;
-- 【sql-03】= NULL 语法不会返回任何结果(错误用法)(返回空集)
SELECT * FROM test_oracle_260527 WHERE col_1 = NULL;
obclient(SYS@oracle_250917)[SYS]> SELECT * FROM test_oracle_260527 WHERE col_1 = '';
Empty set (0.002 sec)
obclient(SYS@oracle_250917)[SYS]> SELECT * FROM test_oracle_260527 WHERE col_1 IS NULL;
+------+-------+
| ID | COL_1 |
+------+-------+
| 1 | NULL |
| 2 | NULL |
+------+-------+
2 rows in set (0.008 sec)
obclient(SYS@oracle_250917)[SYS]> SELECT * FROM test_oracle_260527 WHERE col_1 = NULL;
Empty set (0.004 sec)
在 OB Oracle 模式中:count(col_1) 函数会忽略 NULL 值,正常来说查询结果应该为 2,但是在 OB Oracle 模式中,会将【''(空字符串)】转换成 NULL 值并存储,所以查询结果预期为 1;
-- 【sql-04】验证 count 函数对 null 和 空字符串的处理(预期结果为:1)
SELECT count(col_1) FROM test_oracle_260527;
obclient(SYS@oracle_250917)[SYS]> SELECT count(col_1) FROM test_oracle_260527;
+--------------+
| COUNT(COL_1) |
+--------------+
| 1 |
+--------------+
1 row in set (0.003 sec)
在 OB Oracle 模式中:唯一索引是允许 NULL 值重复的;空字符串会被转换成 NULL 值并存储,所以也是允许重复的;即 2 条 insert 语句都能执行成功;
-- 【sql-05】验证对唯一索引的影响:
CREATE UNIQUE INDEX idx_unique_col_1 ON test_oracle_260527 (col_1); -- 在 col_1 字段上创建唯一索引
INSERT INTO test_oracle_260527 VALUES (4, NULL);
INSERT INTO test_oracle_260527 VALUES (5, '');
obclient(SYS@oracle_250917)[SYS]> CREATE UNIQUE INDEX idx_unique_col_1 ON test_oracle_260527 (col_1);
Query OK, 0 rows affected (0.864 sec)
obclient(SYS@oracle_250917)[SYS]> INSERT INTO test_oracle_260527 VALUES (4, NULL);
Query OK, 1 row affected (0.003 sec)
obclient(SYS@oracle_250917)[SYS]> INSERT INTO test_oracle_260527 VALUES (5, '');
Query OK, 1 row affected (0.003 sec)
PS:本文关于以上所有验证都是在 V 4.2.1.7 版本的 OB 集群中进行。