作者简介:孙占涯,瑞蓝创数据库工程师
原创内容未经授权不得随意使用,转载请联系小编并注明来源
OceanBase 一套内核兼容 MySQL 和 Oracle 两种租户模式,但对NULL、''(空串)的底层处理逻辑天差地别。本文基于 OB V4.2.1.7 实测验证,把两种模式下存储、查询、COUNT 统计、唯一索引四大核心场景讲透,看完直接规避线上故障。
一、总结
【NULL 与空字符串】一句话核心总结:
-
MySQL 模式:空串
''是普通字符串,与NULL完全不同; -
Oracle 模式:空串
''被视为NULL,两者等价;
|
|
|
|
|---|---|---|
''
|
NULL
|
''
|
NULL
|
|
|
NULL
|
|
|
COUNT(column) |
NULL,不统计空串
|
NULL,统计空串
|
NULL
|
|
|
|
|
NULL)
|
|
二、验证步骤-MySQL 模式
2.1 准备环境
创建 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'toclear the currentinput statement.
MySQL [test]> CREATETABLE test_mysql_260527 ( idINT, col_1 VARCHAR(50)); -- 创建测试表
Query OK, 0 rows affected (0.39 sec)
MySQL [test]> INSERTINTO test_mysql_260527 VALUES (1, ''), (2, NULL), (3, 'abc'); -- 插入测试数据,分别是:空字符串,NULL,正常值;
Query OK, 3 rows affected (0.08 sec)
Records: 3 Duplicates: 0 Warnings: 0
2.2 验证 NULL 值和空字符串是否等价
在 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 ISNULL;
+------+-------+
| 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)
2.3 验证 count 函数对 null 和 空字符串的处理
在 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)
2.4 验证对唯一索引的影响
在 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'
三、验证步骤-Oracle 模式
3.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'toclear the currentinput statement.
obclient(SYS@oracle_250917)[SYS]> CREATETABLE test_oracle_260527 ( idINT, col_1 VARCHAR(50)); -- 创建测试表
Query OK, 0 rows affected (0.369 sec)
obclient(SYS@oracle_250917)[SYS]> INSERTINTO test_oracle_260527 VALUES (1, ''), (2, NULL), (3, 'abc'); -- 插入测试数据,分别是:空字符串,NULL,正常值;
Query OK, 3 rows affected (0.054 sec)
Records: 3 Duplicates: 0 Warnings: 0
3.2 验证 NULL 值和空字符串是否等价
使用 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)
3.3 验证 count 函数对 null 和 空字符串的处理
在 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)
3.4 验证对唯一索引的影响
在 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 集群中进行。
END
瑞蓝创 OceanBase OBCP V4 精英训练营
点击下方图片立即了解详情


▼ 点击「阅读原文」,了解更多产品技术文章


