oracle的序列sequence

一、序列定義

序列(SEQUENCE)是序列號生成器,可以爲表中的行自動生成序列號,產生一組等間隔的數值(類型爲數字)。不佔用磁盤空間,佔用內存。其主要用途是生成表的主鍵值,可以在插入語句中引用,也可以通過查詢檢查當前值,或使序列增至下一個值。

二、創建序列

創建序列需要CREATE SEQUENCE系統權限。序列的創建語法如下:

  CREATE SEQUENCE 序列名

  [INCREMENT BY n]

  [START WITH n]

  [{MAXVALUE/ MINVALUE n| NOMAXVALUE}]

  [{CYCLE|NOCYCLE}]

  [{CACHE n| NOCACHE}];

  其中:

1)  INCREMENT BY用於定義序列的步長,如果省略,則默認爲1,如果出現負值,則代表Oracle序列的值是按照此步長遞減的。

2)  START WITH 定義序列的初始值(即產生的第一個值),默認爲1。

3)  MAXVALUE 定義序列生成器能產生的最大值。選項NOMAXVALUE是默認選項,代表沒有最大值定義,這時對於遞增Oracle序列,系統能夠產生的最大值是10的27次方;對於遞減序列,最大值是-1。

4)  MINVALUE定義序列生成器能產生的最小值。選項NOMAXVALUE是默認選項,代表沒有最小值定義,這時對於遞減序列,系統能夠產生的最小值是?10的26次方;對於遞增序列,最小值是1。

5)  CYCLE和NOCYCLE 表示當序列生成器的值達到限制值後是否循環。CYCLE代表循環,NOCYCLE代表不循環。如果循環,則當遞增序列達到最大值時,循環到最小值;對於遞減序列達到最小值時,循環到最大值。如果不循環,達到限制值後,繼續產生新值就會發生錯誤。

6)  CACHE(緩衝)定義存放序列的內存塊的大小,默認爲20。NOCACHE表示不對序列進行內存緩衝。對序列進行內存緩衝,可以改善序列的性能。大量語句發生請求,申請序列時,爲了避免序列在運用層實現序列而引起的性能瓶頸。Oracle序列允許將序列提前生成 cache x個先存入內存,在發生大量申請序列語句時,可直接到運行最快的內存中去得到序列。但cache個數也不能設置太大,因爲在數據庫重啓時,會清空內存信息,預存在內存中的序列會丟失,當數據庫再次啓動後,序列從上次內存中最大的序列號+1 開始存入cache x個。這種情況也能會在數據庫關閉時也會導致序號不連續。

7) NEXTVAL 返回序列中下一個有效的值,任何用戶都可以引用。

8) CURRVAL 中存放序列的當前值,NEXTVAL 應在 CURRVAL 之前指定 ,二者應同時有效。

三、使用序列

調用NEXTVAL將生成序列中的下一個序列號,調用時要指出序列名,即用以下方式調用:

序列名.NEXTVAL

CURRVAL用於產生序列的當前值,無論調用多少次都不會產生序列的下一個值。如果序列還沒有通過調用NEXTVAL產生過序列的下一個值,先引用CURRVAL沒有意義。調用CURRVAL的方法同上,要指出序列名,即用以下方式調用:

序列名.CURRVAL

四、多種序列的創建和使用

(1)最簡單的序列創建:

CREATE SEQUENCE seq_test;

執行這個創建語句會在數據庫中產生一個名字爲seq_test的序列對象,其它的參數都會默認使用默認值。查看生成的源碼如下:

-- Create sequence 
create sequence SEQ_TEST
minvalue 1
maxvalue 999999999999999999999999999
start with 1
increment by 1
cache 20;

當你調用seq_test這個序列時,它會爲你產生從1到999999999999999999999999999的連續遞增數值,從1開始,每次增量爲1,不循環產生。產生最大值後將無法使用。默認使用緩存生成,每次緩存的數量爲20個。

(2)創建有最大值的非循環序列

create sequence seq_test1
increment by 1
start with 10
maxvalue 300
minvalue 5;

這個序列雖然設置最小值爲5,但由於開始值爲10,並且不循環產生,所以不會產生10以下的數值。需要注意的是,序列的起始值不能小於最小值,否則創建序列會報錯。我們把上面代碼改成如下:

create sequence seq_test1
increment by 1
start with 10
maxvalue 300
minvalue 11;


SQL> create sequence seq_test1
  2  increment by 1
  3  start with 10
  4  maxvalue 300
  5  minvalue 11;
create sequence seq_test1
*
ERROR at line 1:
ORA-04006: START WITH cannot be less than MINVALUE

會提示創建失敗。

(3)創建有最大值的循環序列

create sequence seq_test2
increment by 1
start with 10
maxvalue 300 
minvalue 5
cycle ;

當我們執行序列提取到最大值300時,序列會從最小值5開始重新循環生成。而此序列第一次是從開始值生成。需要注意的是,如果是創建一個循環序列,則必須要設定最大值,否則會報錯:

create sequence seq_test2
increment by 1
start with 10
minvalue 5
cycle ;


SQL> create sequence seq_test2
  2  increment by 1
  3  start with 10
  4  minvalue 5
  5  cycle ;
create sequence seq_test2
*
ERROR at line 1:
ORA-04015: ascending sequences that CYCLE must specify MAXVALUE

(4)使用帶緩存的序列

創建序列時使用CACHE能提高性能,特別是在高併發的情況下對數據庫的性能提升還是不錯的。但是使用緩存會有產生斷號的現象,如果你的業務要求序列產生的值必須是連續的,那就只能使用nocache了。cache,它的用處是緩存指定個數的序列值。比如你設置的 cache 是20,那麼在獲取 nextval 時,Oracle 會直接從 cache 中取下一個序列值,如果 cache 中緩存的序列值沒有了(比如 cache 中的序列值用完了,或者被手工清空了),那麼 Oracle 會再次產生20個序列值,並放置 cache 中供使用,這樣有助於提高序列值的獲取速度。

--創建一個帶緩存的序列
create sequence SEQ_CACHE
minvalue 1
maxvalue 1000
start with 1
increment by 1
cache 20;

此時執行SEQ_CACHE.nextval 會返回產生第一個值1。調用SEQ_CACHE.currval 查看當前值爲1。

SQL> select SEQ_CACHE.nextval from dual;

   NEXTVAL
----------
	 1

SQL> select SEQ_CACHE.currval from dual;

   CURRVAL
----------
	 1

當我們第一次調用nextval時,由於設置了緩存數爲20,序列會一次生成20個數值放在緩存裏。當我們再次調用nextval時其實是從緩存裏取到的值。假如我們此時將緩存清空再調用nextval,我們來測試一下。

-- 清空 cache 中緩存的序列值
alter system flush shared_pool;
-- 再次調用nextval獲取序列值
select seq_cache.nextval from dual;
發現獲取的值是21而不是2 。因爲緩存裏的值被清空了,所以系統會自動又獲取20個新的連續值放在緩存裏。

SQL> alter system flush shared_pool;

System altered.

SQL> select seq_cache.nextval from dual;

   NEXTVAL
----------
	21

使用緩存會產生產生的數字不連接的風險,如果系統出異常或oracle重啓則系統會清空緩存的數據,當調用nextval時會重新獲取相應緩存設置的數量的值。

create sequence SEQ_CACHE1
increment by 10
start with 10
maxvalue 300
minvalue 10
cycle
cache 50;


SQL> create sequence SEQ_CACHE1
  2  increment by 10
  3  start with 10
  4  maxvalue 300
  5  minvalue 10
  6  cycle
  7  cache 50;
create sequence SEQ_CACHE1
*
ERROR at line 1:
ORA-04013: number to CACHE must be less than one cycle

我們緩存設定的值是 50,而最大值是 300,那麼爲什麼還會提示這樣的信息呢? 其實我們的 cache 雖然是 50,但是我們每次增長值是 10。這樣 50 次緩存提取出的數是 500 (50*10),我們每次循環的最大值是300,所以就提示我們一次獲取的緩存值必須小於一次循環產生的最大值。

將上面創建序列的語句修改如下:

create sequence SEQ_CACHE1
increment by 10
start with 10
maxvalue 500
minvalue 10
cycle
cache 50;


SQL> create sequence SEQ_CACHE1
  2  increment by 10
  3  start with 10
  4  maxvalue 500
  5  minvalue 10
  6  cycle
  7  cache 50;
create sequence SEQ_CACHE1
*
ERROR at line 1:
ORA-04013: number to CACHE must be less than one cycle

我們一次循環的最大值已經設置成500了,爲什麼還有這樣的錯誤提示?爲什麼還有這樣的錯誤提示?這是因爲還存在一個 minvalue ,minvalue 和 maxvalue 之間是 490 個數,也就是一次循環可以提取 490,但是我們的緩存是500。

create sequence SEQ_CACHE1
increment by 10
start with 10
maxvalue 500
minvalue 9
cycle
cache 50;

發現創建序列成功。在創建序列的時候關於緩存值的設置我們有一個基本的公式要求
最大值-最小值>=(緩存值-1)*每次循環的值

在創建序列時,有如下幾點需要注意,否則序列創建可能不成功。

1、序列第一次必須先調用nextval獲取一個序列值才能使用currval查看當前值

2、序列的起始值不能小於最小值

3、創建一個循環序列,則必須要設定最大值

4、如果創建帶緩存的序列,緩存的值必須滿足約束公式:   最大值-最小值>=(緩存值-1)*每次循環的值

五、修改序列

修改序列的注意事項:

1  必須是序列的擁有者或對序列有 ALTER any sequence權限

2  只有將來的序列值會被改變

3  改變序列的初始值只能通過刪除序列之後重建序列的方法實現
ALTER SEQUENCE emp_sequence INCREMENT BY 10 MAXVALUE 10000 CYCLE;
 
可以影響Sequence的初始化參數:

SEQUENCE_CACHE_ENTRIES =設置能同時被cache的sequence數目。

六、查詢序列

1 通過數據字典DBA_OBJECTS可以查看用戶擁有的序列。

2 通過數據字典DBA_SEQUENCES可以查看序列的設置。

查看用戶的序列:
SELECT SEQUENCE_NAME,MIN_VALUE,MAX_VALUE,INCREMENT_BY,LAST_NUMBER FROM dba_SEQUENCES;

七、刪除序列

drop sequence sequence_name;

八、序列使用場景

(1). 如果一個事務中只是INSERT時需要序列,其他地方不會需要這個序列,那麼只需要在INSERT ... VALUES (seq.nextval ...)語句中使用即可。

(2). 如果一個事務中INSERT一張表後,還需要插入時的主鍵ID值,作爲外鍵插入其他表,那麼就需要在INSERT第一張表前使用select seq.nextval from dual提前獲取可用的ID保存到一個變量中,爲後面使用。

使用序列時Oracle內部大體是按照如下步驟進行:

(1). 一個序列會被定義到Oracle內部的一張數據字典表(seq$)的一行。
(2). 第一次使用序列,序列的起始值會加上緩存大小,然後更新回行。
(3). Oracle內部會自動跟蹤內存中的兩個值,當前值和目標值。
(4). 每次有回話調用seq.nextval,Oracle會遞增當前值,然後檢查是否超過了目標值,再返回結果。
(5). 如果當前值和目標值相同,Oracle會更新數據字典表中的行,爲目標值加上緩存大小,同時內存中產生了一個新的目標值。

例如create sequence seq cache 20;
名稱爲seq的序列,緩存大小是20,默認初始值是1,步長默認是1。
當使用了一次seq.nextval後,可以看HIGHWATER字段值爲21,即目標值1+緩存大小20=21。
當執行20次後,seq.nextval值變爲21,此時HIGHWATER字段值是41,即目標值21+緩存大小20=41。

也就是每調用seq.nextval值20次,會更新一次seq$表,如果cache值較小,且序列使用的頻率較高,那麼會對seq$表有頻繁的更新操作,日誌量會增加,爲了減少這種情況,我們可以將cache緩存值設置大一些,減少對字典表的更新。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章