1. 程式人生 > 其它 >書接上文:薛定諤的貓是如何誕生的?

書接上文:薛定諤的貓是如何誕生的?

編輯手記:注重細節,是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。