not null与check is not null

简介:

在OCP SQL部分有这样一道题:

You need to add a NOT NULL constraint to the QUANTITY column in the PO_DETAIL table. Which statement should you use to complete this task?正确 A. ALTER TABLE po_detail MODIFY (quantity NOT NULL) D. ALTER TABLE po_detail ADD CONSTRAINT quantity_nn NOT NULL(quantity);

NOT NULL ConstraintsA NOT NULL constraint prohibits a column from containing nulls. The NULL keywordby itself does not actually define an integrity constraint, but you can specify it toexplicitly permit a column to contain nulls. You must define NOT NULL and NULLusing inline specification.If you specify neither NOT NULL nor NULL, then the defaultis NULL.

从not null约束的定义我们知道,如果我们要给一个列增加一个not null约束,只能通过modify的方式。那通过add行不行呢?比如alter table po_detail add constraint quantity_nn check(quantity is not null);我们可以通过这种办法达到"not null"的效果那么check is not null既然能达到“not null”的效果,为什么Oracle要提出not null约束呢,两者的区别在哪里?

SQL> create table t(nn number not null,cnn number check(cnn is not null));Table created.

SQL> select constraint_name,constraint_type,search_condition from user_constraints where table_name = 'T';

CONSTRAINT_NAME CONST SEARCH_CONDITIO

--------------- ----- ---------------

SYS_C005420 C "NN" IS NOT NULLSYS_C005421 C cnn is not null

通过上面的例子可以发现,二者的CONSTRAINT_TYPE都是C(CHECK约束),而且,二者的检查条件也几乎完全相同,唯一的区别是,Oracle为NOT NULL约束生成检查条件时自动给列名加上了引号。 Oracle把NOT NULL约束作为约束的一种进行描述,而且为NOT NULL约束提供了专门的语法,难道这一切仅仅是为了方便考虑吗? 下面通过一个例子来看看NOT NULL和CHECK的不同之处。
SQL> create table t1 as select nn,cnn,rowid r from t where 1=0;

Table created.

SQL> desc t1
Name Null? Type
----------------------------------------- -------- ----------------------------
NN NOT NULL NUMBER
CNN NUMBER
R ROWID

SQL> select constraint_name,constraint_type from user_constraints where table_name = 'T1';

CONSTRAINT_NAME CONST
--------------- -----
SYS_C005422 C

SQL> alter table t1 add constraint cons_c_nn check(cnn is not null);

Table altered.

SQL> insert into t1 select nn,cnn,rowid from t;

402550 rows created.

SQL> commit; 

Commit complete.

SQL> create index ind_t1_nn on t1(nn);

Index created.

SQL> exec dbms_stats.gather_table_stats(user,'T1',cascade=>true);

PL/SQL procedure successfully completed.

SQL> set autotrace on;
SQL> select count(*) from t1;

COUNT(*)
----------
402550


Execution Plan
----------------------------------------------------------
Plan hash value: 4079031386

---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 204 (4)| 00:00:03 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| IND_T1_NN | 402K| 204 (4)| 00:00:03 |
---------------------------------------------------------------------------

由于具有NOT NULL约束的列上面存在索引,Oracle认为通过全索引扫描可以得到正确的答案而且速度比全表扫描快,因此执行计划使用了快速全索引扫描。
SQL> drop index ind_t1_nn;

Index dropped.

SQL> create index ind_t1_cnn on t1(cnn);

Index created.

SQL> exec dbms_stats.gather_table_stats(user,'T1',cascade=>true);

PL/SQL procedure successfully completed.

SQL> set autot on;
SQL> select count(*) from t1;

COUNT(*)
----------
402550


Execution Plan
----------------------------------------------------------
Plan hash value: 3724264953

-------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 326 (4)| 00:00:04 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| T1 | 402K| 326 (4)| 00:00:04 |
-------------------------------------------------------------------

SQL> select /*+ index_ffs(t1 ind_t1_cnn) */ count(*) from t1;

COUNT(*)
----------
402550


Execution Plan
----------------------------------------------------------
Plan hash value: 3724264953

-------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 326 (4)| 00:00:04 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| T1 | 402K| 326 (4)| 00:00:04 |
-------------------------------------------------------------------

虽然我们知道,根据CHECK约束的条件,COL_CHECK列上不会存在为空的记录,Oracle使用COL_CHECK上的索引同样可以得到正确的结果,但是Oracle这一次没有使用索引。而且,即使给出了提示,Oracle仍然没有使用索引。这应该是NOT NULL和CHECK的最大区别,NOT NULL成为了列的一种属性,而CHECK是列的数据的限制条件。 Oracle在确定执行计划,考虑是否使用索引的时候,只是检查了列的NOT NULL属性,而没有去检查CHECK约束中的具体约束条件。



本文转自MIKE老毕 51CTO博客,原文链接:http://blog.51cto.com/boylook/1298600,如需转载请自行联系原作者

相关文章
|
11月前
|
关系型数据库 MySQL 开发者
MySQL 字段约束 null, not null, default, auto_increment
前言:转载,觉得有用就发了一遍 在 MySQL 中,每个字段定义都包含附加约束或者修饰符,这些可以用来增加对所输入数据的约束。 今天我们就来看一下 MySQL 的字段约束: NULL 和 NOT NULL 修饰符、DEFAULT 修饰符,AUTO_INCREMENT 修饰符。
167 0
|
关系型数据库 MySQL
MySQL where条件is null 及is not null 的用法
MySQL where条件is null 及is not null 的用法
232 1
MySQL where条件is null 及is not null 的用法
|
SQL 关系型数据库 MySQL
MySQL - IS NOT NULL 和 != NULL 的区别?
MySQL - IS NOT NULL 和 != NULL 的区别?
641 0
|
SQL 缓存 监控
面试题:对NotNull字段插入Null值 有啥现象?
今天我要跟你分享的话题是:“对NotNull字段插入Null值有啥现象?”
156 0
|
关系型数据库 MySQL Java
【MySQL】—— 数据库的约束 (null、unique、primary key、default、foreign key、check)2
【MySQL】—— 数据库的约束 (null、unique、primary key、default、foreign key、check)2
248 0
【MySQL】—— 数据库的约束 (null、unique、primary key、default、foreign key、check)2
|
存储 关系型数据库 MySQL
【MySQL】—— 数据库的约束 (null、unique、primary key、default、foreign key、check)1
【MySQL】—— 数据库的约束 (null、unique、primary key、default、foreign key、check)1
218 0
【MySQL】—— 数据库的约束 (null、unique、primary key、default、foreign key、check)1
|
关系型数据库 MySQL RDS
timestamp类型在not null时可以插入null值?
背景 有同学问在RDS MySQL 5.6在timestamp 设置为 not null 并且SQL模式是严格模式时,仍然可以插入空值,理论上应该有报错,是不是RDS的bug? 环境 MySQL 5.
2436 0
|
SQL
SQL|NULL与IS NOT NULL操作符内涵
可以在不向该列添加值的情况下插入新记录或更新已有的记录。这意味着该字段将以 NULL 值保存。 那么我们如何测试 NULL 值呢? 无法使用比较运算符来测试 NULL 值,比如 =,
1177 0