当主键碰到NULL

简介: 主键和Null看似没有多大的关系,因为一般的主键设置都是not null,但是把两者结合起来,会有很多意想不到的情况,说是意想不到是因为结果不在预期范围,但是如果明白了基本的原理,整个过程又在情理之中。
主键和Null看似没有多大的关系,因为一般的主键设置都是not null,但是把两者结合起来,会有很多意想不到的情况,说是意想不到是因为结果不在预期范围,但是如果明白了基本的原理,整个过程又在情理之中。
我们先来演示一下问题。
首先创建一个表,创建唯一性索引。

SQL> conn n1/n1
Connected.
SQL>
SQL> select*from cat;

no rows selected

SQL> create table test(x number,y number);

Table created.

SQL> create unique index ind_test on test(x,y);

Index created.

SQL> insert into test values(1,2);

1 row created.
再次插入重复的数据,这个肯定会抛错是毫无疑问的。

SQL> insert into test values(1,2);
insert into test values(1,2)
*
ERROR at line 1:
ORA-00001: unique constraint (N1.IND_TEST) violated

然后我们开始测试null相关的场景。
SQL> insert into test values(1,null);

1 row created.

SQL> insert into test values(null,1);

1 row created.
插入两个Null值,也是可以的。

SQL> insert into test values(null,null);

1 row created.
再次插入两个null值,还是可以的。
SQL> insert into test values(null,null);

1 row created.
但是反过来再次插入1,null的时候就抛错了。

SQL> insert into test values(1,null);
insert into test values(1,null)
*
ERROR at line 1:
ORA-00001: unique constraint (N1.IND_TEST) violated

同理,null,1的场景也是如此。
SQL> insert into test values(null,1);
insert into test values(null,1)
*
ERROR at line 1:
ORA-00001: unique constraint (N1.IND_TEST) violated

再次插入两个null值。
SQL> insert into test values(null,null);

1 row created.
查看表test中的数据,如下:

SQL> select *from test;

         X          Y
---------- ----------
         1          2
         1
                    1

 


6 rows selected.
可以看到有6行。null值列看不到任何显示。
为了标识,我们打印出rownum来。

SQL> select rownum,x,y from test;

    ROWNUM          X          Y
---------- ---------- ----------
         1          1          2
         2          1
         3                     1
         4
         5
         6

6 rows selected.
测试完了null值相关的,我们来看看空串''的情况。
插入''的时候就会抛错。

SQL> insert into test values(1,'');
insert into test values(1,'')
*
ERROR at line 1:
ORA-00001: unique constraint (N1.IND_TEST) violated

插入两个空串,和null的效果是一样的。
SQL> insert into test values('','');

1 row created.
null和空串组合,也没有问题。

SQL> insert into test values(null,'');

1 row created.

SQL> insert into test values('','');

1 row created.
再次查看数据,null值的数据行明显增多。

SQL> select rownum,x,y from test;

    ROWNUM          X          Y
---------- ---------- ----------
         1          1          2
         2          1
         3                     1
         4
         5
         6
         7
         8
         9

9 rows selected.

我们可以再进一步,查看null值的长度,使用length()
SQL> select rownum,x,length(x),y,length(y) from test;

    ROWNUM          X  LENGTH(X)          Y  LENGTH(Y)
---------- ---------- ---------- ---------- ----------
         1          1          1          2          1
         2          1          1
         3                                1          1
         4
         5
         6
         7
         8
         9

9 rows selected.
可以看到null值对应的length没有任何显示。
如果用=来匹配空串,和null的效果一样,匹配不了。

SQL> select *from test where x='';

no rows selected
我们还是来看看dump的信息吧,对于null列dump的结果就是null

  1* select rownum,x,y,dump(x) from test
SQL> /

    ROWNUM          X          Y DUMP(X)
---------- ---------- ---------- ------------------------------
         1          1          2 Typ=2 Len=2: 193,2
         2          1            Typ=2 Len=2: 193,2
         3                     1 NULL
         4                       NULL
         5                       NULL
         6                       NULL
         7                       NULL
         8                       NULL
         9                       NULL

9 rows selected.

感觉null值还是一个很有意思的话题,如果在查询中使用了 where xxx is null的方式,就不会走索引扫描,
而如果表中没有not null的约束,这可能会牵扯到一个全表扫描的案例
 我们还是创建一个新表a,然后字段Object_id上没有not null约束

SQL> create table a as select object_id,object_name,object_type from dba_objects;
Table created.

SQL> desc a
 Name                                                  Null?    Type
 ----------------------------------------------------- -------- ------------------------------------
 OBJECT_ID                                                      NUMBER
 OBJECT_NAME                                               VARCHAR2(128)
 OBJECT_TYPE                                               VARCHAR2(19)

SQL> analyze table a compute statistics;
Table analyzed.
Dbms_stats.gather_table_stats;
SQL> create unique index ind_a on a(object_id);
Index created.

SQL> set autot traceonly exp
如果根据object_id来查询,是会走唯一性扫描。

但是如果查看所有object_id的值,就会走全表扫描。如果查看object_id为null的行,发现时0条。

如果加入了not null约束,就会走fast full scan了。

可见null值对于索引扫描的影响确实是非常巨大,需要在写sql语句的时候提前注意到这个问题。

目录
打赏
0
0
0
0
16
分享
相关文章
PolarDB产品使用问题之主键为NULL是什么导致的
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。
【MySQL进阶之路丨第十一篇】一文带你精通MySQL NULL值处理、正则表达式
【MySQL进阶之路丨第十一篇】一文带你精通MySQL NULL值处理、正则表达式
150 0
实时计算 Flink版产品使用合集之从MySQL同步数据到Doris时,历史数据时间字段显示为null,而增量数据部分的时间类型字段正常显示的原因是什么
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStreamAPI、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
python在mysql中插入或者更新null空值
这段代码是Python操作MySQL数据库的示例。它执行SQL查询从表`a_kuakao_school`中选取`id`,`university_id`和`grade`,当`university_id`大于0时按升序排列。然后遍历结果,根据`row[4]`的值决定`grade`是否为`NULL`。若不为空,`grade`被格式化为字符串;否则,设为`NULL`。接着构造UPDATE语句更新`university`表中对应`id`的`grade`值,并提交事务。重要的是,字符串`NULL`不应加引号,否则更新会失败。
283 2
mysql不等于<>取特定值反向条件的时候字段有null值或空值读取不到数据
对于数据库开发的专业人士来说,理解NULL的特性并知道如何正确地在查询中处理它们是非常重要的。以上所介绍的技巧和实例可以帮助你更精准地执行数据库查询,并确保数据的完整性和准确性。在编写代码和设计数据库结构时,牢记这些细节将有助于你避免许多常见的错误,提高数据库应用的质量与性能。
395 0
MySQL设计规约问题之为什么应该把字段定义为NOT NULL并且提供默认值
MySQL设计规约问题之为什么应该把字段定义为NOT NULL并且提供默认值
MySQL外键约束行为解析:CASCADE, NO ACTION, RESTRICT, SET NULL
MySQL外键约束行为解析:CASCADE, NO ACTION, RESTRICT, SET NULL
1570 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问