Oracle列自增-Identity Columns in Oracle Database 12c Release 1 (12.1)
在ORACLE 12C以前的版本中,如果要實現列自增長,需要通過序列+觸發器實現,到了12C ORACLE 引進了Identity Columns新特性,從而實現了列自增長功能。
一、Identity Columns使用語法
GENERATED [ ALWAYS | BY DEFAULT [ ON NULL ] ] AS IDENTITY [ ( identity_options ) ]identity_options
二、identity_clause
2.1 ALWAYS選項
DROP TABLE IDENTITY_TEST_TAB PURGE; CREATE TABLE identity_test_tab ( id NUMBER GENERATED ALWAYS AS IDENTITY, description VARCHAR2(30) );
插入測試1:
INSERT INTO identity_test_tab (description) VALUES ('Just DESCRIPTION')
[SQL]INSERT INTO identity_test_tab (description) VALUES ('Just DESCRIPTION')
受影響的行: 1
時間: 0.008s
插入測試2:
INSERT INTO identity_test_tab (id, description) VALUES (NULL, 'ID=NULL and DESCRIPTION')
[SQL]INSERT INTO identity_test_tab (id, description) VALUES (NULL, 'ID=NULL and DESCRIPTION')
[Err] ORA-32795: cannot insert into a generated always identity column 無法插入到“始終生成”身份列
插入測試3:
INSERT INTO identity_test_tab (id, description) VALUES (999, 'ID=999 and DESCRIPTION')
[SQL]INSERT INTO identity_test_tab (id, description) VALUES (999, 'ID=999 and DESCRIPTION')
[Err] ORA-32795: cannot insert into a generated always identity column
更新測試:
UPDATE IDENTITY_TEST_TAB SET ID=2 WHERE ID=1
[SQL]UPDATE IDENTITY_TEST_TAB SET ID=2 WHERE ID=1
[Err] ORA-32796: cannot update a generated always identity column
結論:
- GENERATED ALWAYS AS IDENTITY 可以不指定該列進行插入
- GENERATED ALWAYS AS IDENTITY不能在該列中插入NULL值
- GENERATED ALWAYS AS IDENTITY不能指定具體值插入
- GENERATED ALWAYS AS IDENTITY 不能使用update更新該列
2.2 BY DEFAULT
選項
DROP TABLE identity_test_tab PURGE; CREATE TABLE identity_test_tab ( id NUMBER GENERATED BY DEFAULT AS IDENTITY, description VARCHAR2(30) );
插入測試1:
INSERT INTO identity_test_tab (description) VALUES ('Just DESCRIPTION');
[SQL]INSERT INTO identity_test_tab (id, description) VALUES (999, 'ID=999 and DESCRIPTION')
受影響的行: 1
時間: 0.001s
SELECT * FROM identity_test_tab;
插入測試2:
INSERT INTO identity_test_tab (id, description) VALUES (999, 'ID=999 and DESCRIPTION');
[SQL]INSERT INTO identity_test_tab (id, description) VALUES (999, 'ID=999 and DESCRIPTION')
受影響的行: 1
時間: 0.001s
SELECT * FROM identity_test_tab;
插入測試3:
INSERT INTO identity_test_tab (id, description) VALUES (NULL, 'ID=NULL and DESCRIPTION');
[SQL]INSERT INTO identity_test_tab (id, description) VALUES (NULL, 'ID=NULL and DESCRIPTION')
[Err] ORA-01400: cannot insert NULL into ("TEST_USER"."IDENTITY_TEST_TAB"."ID")
更新測試:
UPDATE IDENTITY_TEST_TAB SET ID=2 WHERE ID=1
[SQL]UPDATE IDENTITY_TEST_TAB SET ID=2 WHERE ID=1
受影響的行: 1
時間: 0.001sUPDATE IDENTITY_TEST_TAB SET ID=2 WHERE ID=1
結論:
- GENERATED BY DEFAULT AS IDENTITY 可以不指定該列進行插入
- GENERATED BY DEFAULT AS IDENTITY 可以指定具體值插入
- GENERATED BY DEFAULT AS IDENTITY 不能在該列中插入null值
- 可以使用update更新該列,但不能更新為NULL
2.3 DEFAULT ON NULL
選項
DROP TABLE identity_test_tab PURGE; CREATE TABLE identity_test_tab ( id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY, description VARCHAR2(30) );
插入測試:
INSERT INTO identity_test_tab (description) VALUES ('Just DESCRIPTION'); INSERT INTO identity_test_tab (id, description) VALUES (999, 'ID=999 and DESCRIPTION'); INSERT INTO identity_test_tab (id, description) VALUES (NULL, 'ID=NULL and DESCRIPTION');
[SQL]INSERT INTO identity_test_tab (description) VALUES ('Just DESCRIPTION')
受影響的行: 1
時間: 0.003s
[SQL]INSERT INTO identity_test_tab (id, description) VALUES (999, 'ID=999 and DESCRIPTION')
受影響的行: 1
時間: 0.001s
[SQL]INSERT INTO identity_test_tab (id, description) VALUES (NULL, 'ID=NULL and DESCRIPTION')
受影響的行: 1
時間: 0.002s
SELECT * FROM identity_test_tab;
更新測試
UPDATE IDENTITY_TEST_TAB SET ID=3 WHERE ID=1
[SQL]UPDATE IDENTITY_TEST_TAB SET ID=3 WHERE ID=1
受影響的行: 1
時間: 0.004s
結論:
- GENERATED BY DEFAULT ON NULL AS IDENTITY 可以不指定該列進行插入
- GENERATED BY DEFAULT ON NULL AS IDENTITY 方式可以指定具體值插入
- GENERATED BY DEFAULT ON NULL AS IDENTITY 可以在該列中插入null值
- 可以使用update更新該列
三、原理
3.1 Identity Columns 是基於序列實現的
使用此語法實現ID自增,要求必須有創建序列的權限。可以推測是基於序列實現的
執行完建表語句后:
CREATE TABLE identity_test_tab ( id NUMBER GENERATED ALWAYS AS IDENTITY, description VARCHAR2(30) );
查看user_objects
SELECT object_name, object_type FROM user_objects;
發現建表的時候自動生成了一個sequence
SELECT table_name, column_name, generation_type, identity_options FROM all_tab_identity_cols WHERE owner = 'TEST_USER';
表和sequence的關系存在SYS.IDNSEQ$
表中
Sys
登陸查看
SELECT a.name AS table_name, b.name AS sequence_name FROM sys.idnseq$ c JOIN obj$ a ON c.obj# = a.obj# JOIN obj$ b ON c.seqobj# = b.obj# where a.name='IDENTITY_TEST_TAB';
3.2 GENERATED IDENTITY 中sequence不能單獨被刪除
DROP TABLE IDENTITY_TEST_TAB
刪除表后,該sequence還存在。且該sequence無法被刪除
必須
purge table IDENTITY_TEST_TAB,
結論:
- Identity Columns 是基於序列實現的
- GENERATED IDENTITY 中sequence不能單獨被刪除
- GENERATED IDENTITY 中的表刪除,如果存在回收站中,該sequence依然存儲,如果表被徹底刪除,則sequence也被刪除
3.3 執行插入語句時的解釋計划
INSERT INTO identity_test_tab (description) VALUES ('Just DESCRIPTION');
對比發現:該方式的效率比觸發器+序列的方式高!
四、identity_options
查看表的DDL
select dbms_metadata.get_ddl('TABLE','IDENTITY_TEST_TAB') FROM DUAL;
CREATE TABLE "TEST_USER"."IDENTITY_TEST_TAB"
( "ID" NUMBER GENERATED ALWAYS AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE NOT NULL ENABLE,
"DESCRIPTION" VARCHAR2(30)
) 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"
INCREMENT BY
用於定義序列的步長,如果省略,則默認為1,如果出現負值,則代表序列的值是按照此步長遞減的。
START WITH
定義Oracle序列的初始值(即產生的第一個值),默認為1。
MAXVALUE
定義序列生成器能產生的最大值。選項NOMAXVALUE是默認選項,代表沒有最大值定義,這時對於遞增序列,系統能夠產生的最大值是10的27次方;對於遞減序列,最大值是-1。
MINVALUE
定義序列生成器能產生的最小值。選項NOMAXVALUE是默認選項,代表沒有最小值定義,
CYCLE和NOCYCLE
表示當序列生成器的值達到限制值后是否循環。CYCLE代表循環,NOCYCLE代表不循環。如果循環,則當遞增序列達到最大值時,循環到最小值;對於遞減序列達到最小值時,循環到最大值。如果不循環,達到限制值后,繼續產生新值就會發生錯誤。
CACHE
(緩沖)定義存放序列的內存塊的大小,默認為20。NOCACHE表示不對序列進行內存緩沖。對序列進行內存緩沖,可以改善序列的性能。
原文地址:
ORACLE 12C 新特性Identity Columns—實現ORACLE自增長列功能