ORACLE SEQUENCE
ORACLE沒有自增數據類型,如需生成業務無關的主鍵列或惟一約束列,可以用sequence序列實現。
CREATE SEQUENCE語句及參數介紹:
創建序列:需要有CREATE SEQUENCE或者CREATE ANY SEQUENCE權限,
CREATE SEQUENCE [ schema. ]sequence
[ { INCREMENT BY | START WITH } integer
| { MAXVALUE integer | NOMAXVALUE }
| { MINVALUE integer | NOMINVALUE }
| { CYCLE | NOCYCLE }
| { CACHE integer | NOCACHE }
| { ORDER | NOORDER }
];
CREATE SEQUENCE各參數詳解:
schema指定在哪個用戶的schema下創建sequence,如不指定,默認在當前用戶下創建。
sequence指定要創建的sequence序列名
注意:如果只指定以上參數,將啟動一個從1開始,以1為單位遞增,沒有最大值限制的遞增序列。
如果要創建一個沒有約束的序列,遞增序列時:忽略MAXVALUE參數或指定NOMAXVALUE;遞減序列:省略MINVALUE參數或指定NOMINVALUE。
如果要創建一個有限制的序列,遞增序列時:指定MAXVALUE參數;遞減序列:指定MINVALUE參數。此時序列達到限制後會報錯:
如果要創建一個有限制的序列在達到限制後重新啟動,指定MAXVALUE和MINVALUE後,還需要指定CYCLE。如果不指定MINVALUE,默認為NOMINVALUE,
這個值是1.
INCREMENT BY指定序列號間的間隔,這個整數值可以是任何正整數或負整數,但不能是0。這個值最多有28位數字。
絕對值必須小於MAXVALUE與MINVALUE的差異(如非在此區間報錯:ORA-04005: INCREMENT must be less than MAXVALUE minus MINVALUE)。
如果這個值是負的,則該序列下降。如果該值為正,則序列上升。如果省略此子句,則間隔缺省為1。
START WITH指定要產生的第一個序列號。
此子句啟動一個遞增序列,要大於最小值;或啟動一個遞減序列,小於它最大值。
對於遞增序列,默認值是序列中的最小值。對於遞減的序列,默認值是序列中的最大值。這個整數值可以最多28位數字。
這個值和達到限制的最大/最小值後重新啟動時的值沒有關系(如遞增序列創建時指定有最大值最小值且指定CYCLE,則序列達到最大值後,
會從最小值開始;如未指定兼包最小值,默認1開始。
MaxValue指定序列可生成的最大值。這個整數值可以最多28位數字。MAXVALUE必須>=START WITH、必須大於MINVALUE。
NOMAXVALUE:指定NOMAXVALUE表示遞增序列的最大值是10的27次方,或遞減序列最大值為-1。這是默認的。
MINVALUE:指定序列的最小值。這個整數值可以最多28位數字。MINVALUE必須<=START WITH的值和必須小於MAXVALUE。
如此處不符,報:ORA-04006: START WITH cannot be less than MINVALUE。不指定此參數時,默認是1.
NOMINVALUE:指定NOMINVALUE來表示遞增的序列最小值為1,遞減序列為負10的26次方。這是默認的。
CYCLE:指定循環,表明序列在達到它的最大或最小值後生成的值。當遞增序列達到最大值後,再從最小值開始循環。
當遞減序列達到最小值,從最大值開始循環。
NOCYCLE:指定NOCYCLE以指示該序列不能在達到其最大值或最小值後產生更多的值。這是默認的。
CACHE :指定數據庫為序列預分配多少個值放在內存中以便更快訪問。這個整數值可以最多28位數字。該參數最小值為2;
這個值必須小於一個CYCLE循環的數(比如從1-100是一個循環,CACHE要小於100,不然可能 一次CACHE的值要有重復的會出錯。
報錯是:ORA-04013: number to CACHE must be less than one cycle)。
計算公式是:(CEIL (MAXVALUE - MINVALUE)) / ABS (INCREMENT)
如果系統故障,內存中未使用的CACHE值會丟失,將會導致序列不連續。ORACLE建議在RAC中使用CACHE來提高性能。
NOCACHE :指定該序列值不被預分配。如果省略CACHE和NOCACHE,數據庫默認會緩存20個序列號。
ORDER :只有在RAC時需要指定,指定ORDER 是為了保證序列號是因為有請求才生成的。在使用序列號做為一個時間戳時很有用。
NOORDER:這是默認的。
使用序列
序列生成的是一系列整數數字.一個序列中包含兩個"偽列" ,分別為"Currval"和"Nextval",可以分別用來獲取該序列的當前值和下一個值.
雖然我們在定義時指定序列初始值為1但並沒有真正初始化該值. 當在檢索序列的當前值前,必須通過檢索序列的下一個值即Nextval來對序列進行
初始化操作.在選擇了Nextval時,該序列就被初始化為1.
使用sequence時對系統性能大致有以下影響:
詳見:http://blog.itpub.net/17203031/viewspace-717042
1.Seq$基表是記錄系統sequence的數據字典表.每次調用nextval,會遞歸調用更新並COMMIT Seq$基表。
2.更新Seq$基表並提交會產生redo log--幾百字節,COMMIT頻繁會造成LGWR的壓力;過多redo log生成,造成LGWR壓力、恢復時費時等。
3.多個會話使用sequence可能出現爭用,等待事件row lock contention
對於nocache/cache參數:
nocache:每次使用nextval,都會更新Seq$基表並COMMIT。
cache:只有在內存中cache的序列號使用完後才會重新獲取sequence,才會更新Seq$基表並提交。
比如cache設置為2000,則在使用sequence時對性能影響比nocache小上千倍。
所以一般情況下,建議設置一個較大的cache值,用於進行性能的優化。(默認不指定nocache時是20)
#####################################################
ORACLE sequence創建示例:
create sequence bys.test_seq
increment by 3
start with 5
maxvalue 18
minvalue 4
cycle
cache 4;
在bys用戶下創建名為test_seq的sequence
從5開始,每次增加3,最大值是18,最小值是4
允許重用,cache 4 表示會緩存四個序列號,比如5 8 11 14
當然在實驗中也可以使用最簡單的:create sequence bys.test_seq2; 其它參數不寫,使用系統默認哈哈
#####################################################
ORACLE sequence修改和刪除示例:
ALTER SEQUENCE [ schema. ]sequence
{ INCREMENT BY integer
| { MAXVALUE integer | NOMAXVALUE }
| { MINVALUE integer | NOMINVALUE }
| { CYCLE | NOCYCLE }
| { CACHE integer | NOCACHE }
| { ORDER | NOORDER }
}
修改時的三個注意事項:
如果要使序列start with不同的數字,只能刪除序列重建。
如果在使用NEXTVAL初始化序列前改變INCREMENT BY的值,一些序列號會被跳過。解決跳過問題的方法--刪除重建
修改的各個參數的新值依然要滿足create sequence各參數介紹中的描述。
NEXTVAL初始化序列前改變INCREMENT BY的值示例:
create sequence bys.seq3
increment by 3
start with 5
maxvalue 18
nominvalue
cycle
cache 4;
BYS@ bys3>alter sequence bys.seq3 increment by 5; --初始化前修改
Sequence altered.
BYS@ bys3>select seq3.nextval from dual; --初始化時確實跳過了一些數字。。
NEXTVAL
----------
7
BYS@ bys3>select seq3.nextval from dual;
NEXTVAL
----------
12
示例修改語句:
ALTER SEQUENCE customers_seq MAXVALUE 1500;
ALTER SEQUENCE customers_seq CYCLE CACHE 5;
刪除序列語句:
DROP SEQUENCE [ schema. ]sequence_name ;
如:BYS@ bys3>drop sequence bys.seq2;
############################
ORACLE sequence使用示例
詳見官方文檔--http://docs.oracle.com/cd/B19306_01/server.102/b14200/pseudocolumns002.htm#i1006157
序列常見使用場景:
1可以在SELECT 語句,CREATE TABLE ... AS SELECT語句, CREATE MATERIALIZED VIEW ... AS SELECT中使用。
2在UPDATE的SET中,在INSERT 的子句或VALUES中。序列可以由多個用戶同時訪問而不產生等待或鎖定。
3第一次查詢要用 NEXTVAL,返回序列的初始值。
4查詢當前序列號用:CURRVAL,返回的是最後一次引用NEXTVAL返回的值。
5查詢下一個序列號用NEXTVAL--用此命令時,sequence會先增加1或increment by指定的值,然後返回sequence值
本實驗中的查詢:
BYS@ bys3>select test_seq.currval from dual; ---未使用NEXTVAL初始化,故報此錯。
select test_seq.currval from dual
*
ERROR at line 1:
ORA-08002: sequence TEST_SEQ.CURRVAL is not yet defined in this session
BYS@ bys3>select test_seq.nextval from dual; 第一次使用NEXTVAL,顯示的是創建時start with指定的值
NEXTVAL
----------
5
BYS@ bys3>select test_seq.currval from dual; 使用currval查到當前序列號---最後一次引用NEXTVAL返回的值
CURRVAL
----------
5
BYS@ bys3>select test_seq.nextval from dual; --一直執行nextval,觀察序列達到maxvalue指定的值後如何循環使用
NEXTVAL
----------
17
BYS@ bys3>select test_seq.nextval from dual; --序列達到maxvalue指定的值後返回的是minvalue指定的值而不是start with了。如未指定minvalue或指定NOMINVALUE,則是返回1.
NEXTVAL
----------
4
BYS@ bys3>insert into test values(test_seq.nextval,'seqtest'); --使用INSERT語句調用序列
1 row created.
BYS@ bys3>select * from test;
OBJECT_NAME STATUS
------------ -------
10 seqtest
BYS@ bys3>insert into test values(test_seq.currval,'seqtest');
1 row created.
BYS@ bys3>select * from test;
OBJECT_NAME STATUS
------------ -------
10 seqtest
10 seqtest
BYS@ bys3>insert into test(object_name) select test_seq.nextval from dual; --使用INSERT子語調用序列
1 row created.
BYS@ bys3>select * from test;
OBJECT_NAME STATUS
------------ -------
10 13
10 16
4
BYS@ bys3>update test set status=test_seq.nextval; --使用UPDATE語句調用序列
2 rows updated.
BYS@ bys3>select * from test;
OBJECT_NAME STATUS
------------ -------
10 13
10 16
BYS@ bys3>delete test where status=test_seq.currval; --DELETE中不能使用sequence做條件
delete test where status=test_seq.currval
*
ERROR at line 1:
ORA-02287: sequence number not allowed here
利用解發器自動為表插入遞增序列:---類似自增字段的作用
建解發器代碼為:
create or replace trigger tri_test_id
before insert on test --test 是表名
for each row
declare
nextid number;
begin
IF :new.testid IS NULL or :new.testid=0 THEN --DepartId是列名
select seq1.nextval --seq1是提前創建好的序列的名字
into nextid from sys.dual;
:new.testid:=nextid;
end if;
end tri_test_id;