書接上文:薛定諤的貓是如何誕生的?
編輯手記:注重細節,是DBA必要的基本素質要求。
書接上文(參考:空與非空 - 資料庫中也有薛定諤的貓?),其實CBO的判斷本身是沒有問題的,問題在於,為什麼一個空值會存在非空約束的欄位中。
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"
之前提到,由於TYPE列具有非空約束,導致CBO給出的執行計劃返回了錯誤的結果,但是問題的根源在於,為什麼Oracle會允許空值插入到非空約束欄位中:
SQL> insert into t_def (id, name) values (1, 'a');
insert into t_def (id, name) values (1, 'a')
*
ERROR at line 1:
ORA-01400: cannot insert NULL into ("TEST"."T_DEF"."TYPE")
那麼是什麼情況導致了錯誤的資料繞過了Oracle的檢查呢。檢查表的定義,發現一個特別之處,TYPE列的預設值本身就是NULL,是不是這個導致了Oracle的資料問題呢:
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")
顯然問題沒有那麼簡單,雖然預設值人為設定為NULL並不常見,但是對於哪些具有NOT NULL約束且沒有指定預設值的列,都相當於預設值為NULL。顯然不太可能是常規問題導致的bug,Oracle經過這麼多年這麼多版本的磨練,應該不會在11g還出現這種問題,而且這個問題還是第一次碰到。綜上所述,推斷問題可能是11g新特性所引入的bug。
分析到這裡,問題的答案也呼之欲出了,沒錯,導致問題的就是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值。
而且由於指定的DEFAULT是NULL,ECOL$中居然沒有記錄任何資訊:
SQL> select * from sys.ecol$;
no rows selected
看來任何新特性都難以避免BUG的產生,沒想到一個增加非空預設值的新特性也會引發BUG。