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 集群中进行。
如果在操作过程中遇到问题,欢迎在评论区留言交流,后续我们会持续分享更多实战运维干货,记得
关注不迷路,下次见~
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70047467/viewspace-3175512/ ,如需转载,请注明出处,否则将追究法律责任。