YUNHE ENMO (BEIJING) TECHNOLOGY CO.,LTD 从菜鸟到专家成 …
Transcript of YUNHE ENMO (BEIJING) TECHNOLOGY CO.,LTD 从菜鸟到专家成 …
云和恩墨 成就所托 云和恩墨 成就所托 云和恩墨 成就所托
从菜鸟到专家成长系列之一 大梦初醒
云和恩墨(北京)信息技术有限公司
ACE:侯圣文、李轶楠、杨廷琨、张乐奕
YUNHE ENMO (BEIJING) TECHNOLOGY CO.,LTD
云和恩墨 成就所托 云和恩墨 成就所托
故事背景: 使用同步软件,把源端数据同步到目标端时,产生了报错。
Release 11.2.0.3.0
报 错:
ERROR at line 1:
ORA-01400: cannot insert NULL into ("TEST"."T_PROD"."TYPE")
人物角色: 甲方老总 ------ 杨廷琨 乙方主管 ------ 张乐奕 乙方驻场DBA ------ 李轶楠 恩墨学院院长 ------ 侯圣文
云和恩墨 成就所托 云和恩墨 成就所托
行级锁 Oracle
事务
日志挖掘
小小DBA:哎呦,这个问题很简单了撒。一定是你那个Type字段不能为空值,可是你插入的数据是null,所以报错。您修改程序,或者把错误的数据删掉就可以了。 甲方老总:报错的原因是什么?为什么源数据库没有问题?
……
云和恩墨 成就所托 云和恩墨 成就所托
行级锁 Oracle
事务
日志挖掘
SQL> select * from t_def;
ID NAME TYPE
---------- ------------------------------ --------
1 a
这不科学!
云和恩墨 成就所托 云和恩墨 成就所托
行级锁 Oracle
事务
日志挖掘
SQL> select dump(type) from t_def;
DUMP(TYPE)
--------------------------------------------
NULL
SQL> select nvl(type, 'is null') from t_def;
NVL(TYPE
--------
is null
SQL> select * from t_def where type is null;
no rows selected
SQL> select * from t_def where type is not null;
ID NAME TYPE
---------- ------------------------------ --------
1 a
云和恩墨 成就所托 云和恩墨 成就所托
第一个查询和第二个查询明确的告诉我们,TYPE列
的值不是NULL值 第三个查询和第四个查询又确切告之我们,TYPE列
是NULL值 到底TYPE列的值是NULL还是NOT NULL呢?
这是一个问题!
云和恩墨 成就所托 云和恩墨 成就所托
查查数据到底是什么样的
看块结构,dump dump块
云和恩墨 成就所托 云和恩墨 成就所托
行级锁 Oracle
事务
日志挖掘
案例分析
SQL> select dbms_rowid.rowid_relative_fno(rowid), dbms_rowid.rowid_block_number(rowid)
from t_def;
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
------------------------------------ -----------------------------------
4 73109
SQL> alter system dump datafile 4 block 73109;
System altered.
云和恩墨 成就所托 云和恩墨 成就所托
Block header dump: 0x0102a435
Object id on Block? Y
seg/obj: 0x145df csc: 0x00.23b6097 itc: 2 flg: E typ: 1 - DATA
brn: 0 bdba: 0x102a430 ver: 0x01 opc: 0
inc: 0 exflg: 0
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0008.01b.00001afc 0x00c026de.11be.10 --U- 1 fsc 0x0000.023b6098
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
bdba: 0x0102a435
data_block_dump,data header at 0x7fe7fdc97264
===============
……
block_row_dump:
tab 0, row 0, @0x1f90
tl: 8 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 2] c1 02
col 1: [ 1] 61
end_of_block_dump
End dump data blocks tsn: 4 file#: 4 minblk 173109 maxblk 173109
云和恩墨 成就所托 云和恩墨 成就所托
根据实际的存储得知,Type列确实为空。
可是,为什么用“select * from t_def where
type is null”查看,Oracle会告诉我们一个错
误的结果呢?
云和恩墨 成就所托 云和恩墨 成就所托
行级锁 Oracle
事务
日志挖掘
SQL> set autot on exp
SQL> select * from t_def where type is null;
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 177263571
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 | 0 (0)| |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS FULL| T_DEF | 1 | 5 | 3 (0)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(NULL IS NOT NULL)
云和恩墨 成就所托 云和恩墨 成就所托
SQL> select * from t_def where type is not null;
ID NAME TYPE
---------- -------- --------
1 a
Execution Plan
----------------------------------------------------------
Plan hash value: 1057129282
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| T_DEF | 1 | 5 | 3 (0)| 00:00:01 |
---------------------------------------------------------------------------
云和恩墨 成就所托 云和恩墨 成就所托
由于表中的TYPE列具有非空约束(not null),导致CBO给出的执行计划返回了错误的结果。
当限定条件为:where type is null时,CBO认为此查询与约束相悖,自动添加了一个(null is not
null)的过滤,返回零行结果。
云和恩墨 成就所托 云和恩墨 成就所托
Why:该列中
会有空值? How:数据怎么
绕过非空约束的?
云和恩墨 成就所托 云和恩墨 成就所托
SQL> select dbms_metadata.get_ddl('TABLE', 'T_DEF') from dual;
DBMS_METADATA.GET_DDL('TABLE','T_DEF')
---------------------------------------------------------
CREATE TABLE "TEST"."T_DEF"
( "ID" NUMBER,
"NAME" VARCHAR2(8) DEFAULT 'a',
"TYPE" VARCHAR2(8) DEFAULT '' NOT NULL ENABLE
) SEGMENT CREATION IMMEDIATE
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS
2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE
DEFAULT)
TABLESPACE "USERS"
查询表结构
云和恩墨 成就所托 云和恩墨 成就所托
SQL> CREATE TABLE T_TEST (ID NUMBER, NAME VARCHAR2(30) DEFAULT '' NOT
NULL);
表已创建。
SQL> INSERT INTO T_TEST (ID) VALUES (1);
INSERT INTO T_TEST (ID) VALUES (1)
*
第 1 行出现错误:
ORA-01400: 无法将 NULL 插入 ("TEST"."T_TEST"."NAME")
测试:如果列上有非空约束,即使该列default是null值,也是无法插入null值的
云和恩墨 成就所托 云和恩墨 成就所托
云和恩墨 成就所托 云和恩墨 成就所托
Null
• Not Null约束
• CBO优化器
Oracle 11g新特性
• Default
•快速添加非空默认值
版本演进
• 10g---null is not null执行计划
• 11g
云和恩墨 成就所托 云和恩墨 成就所托
快速添加非空默认值
SQL> create table t_def (id number, name varchar2(30) default '' not null);
Table created.
SQL> insert into t_def values (1, 'a');
1 row created.
SQL> alter table t_def add type varchar2(8) default '' not null;
Table altered.
SQL> select * from t_def;
ID NAME TYPE
---------- -------------------------------------------- --------
1 a
Oracle确实允许NOT NULL列的默认值为NULL,如果不指定默认值那么就相当于默认值为NULL,但是
对于11g新增的新特性而言,DEFAULT为NULL是要禁止的,否则就会导致现有记录的NOT NULL字段出
现NULL值。
云和恩墨 成就所托 云和恩墨 成就所托
Weibo:@恩墨学院
网 站:http://www.enmoedu.com
Email:[email protected]
电 话:400-660-8755
13552144418
云和恩墨 成就所托 云和恩墨 成就所托