我的上兩個專欄中已經介紹到了與版本 8 功能相關的主題。我們可能需要在今天設計的數據庫和應用程序中考慮這些功能。我們已經談論了新的數據分區的輔助索引和附加的索引修改。在上一期中,我們了解了 DSSIZE 如何可以影響今后的分區策略。現在,我想要簡要地來介紹一下 Sequence 對象以及如何用它們來代替 Identity 列。我們還將介紹版本 8 中一些用以使用 Identity 列的新功能。
過去的許多應用程序都需要能夠生成序號(例如獲取下一個可用的帳號)。問題是該工作通常是通過用單個控制表存儲這些數字,然后用可重復讀(Repeatable Read)的 SELECT MAX 在隨后的 INSERT 中檢索並使用該數字來完成的。常常有多個事務需要使用該表,而這就導致了應用程序中無法解決的單點競爭。這是由於每次只有一個事務可以檢索下一值,因為事務必須鎖定該表以使數字增量。請參閱圖 1。
在過去多年中曾經嘗試過許多創造性的解決方案,例如使用行級的鎖定,但是這些技術產生的系統開銷加上成千上萬個並發事務間的沖突仍然會導致性能瓶頸。如果用於數據共享的環境中,其中將有多個成員使用該表,那么它也會導致單點故障並且產生巨大的鎖定開銷。
![]() ![]() |
![]() |
因而在較晚的版本 6 中就出現了 Identity 列,用以解決前面提到的問題。如果一個表指派了 Identity 列,那么當向該表插入一行時,將根據 Identity 列的定義(START WITH 和 INCREMENT BY 值)來填充它。雖然使用 Identity 列要遠勝於使用單個控制表,但是 Identity 列在使用方面卻非常有限並且存在管理問題。
在版本 8 之前,Identity 列還帶來了一些問題,例如:
- 如何獲得 Identity 列的值來填充 RI 有關的表?
- 如何在插入之前獲取值?
- 如何重新設置或更改 Identity 列的值?
這還僅僅只是一部分問題。許多公司圍繞這些問題開發了一種方法,他們從表中刪除 Identity 列然后創建一個只含 Identity 列及其生成值的表。因此,上述問題,例如重新開始 Identity 列的值或填充 RI 有關的表,都可以通過使 Identity 列與表分離而得到解決。該技術仍然允許由 DB2 來填充 Identity 列的值,並且減少了許多限制。但還是必須要對該表進行填充、訪問和維護,並且它無法解決 Identity 列的所有問題以及無法完全開發與由 DB2 執行數字生成相關的潛在性能。圖 2 是一個展示如何使用該技術的例子。
版本 8 已經緩解了上述 Identity 列的部分問題,例如使用 SELECT 功能中的新的 INSERT 進行插入之前可以獲得 Identity 列的值。下面這個例子展示了如何在插入時使用該功能來獲取 Identity 列的值。
(假定所創建的表以自動生成的 ACCT_ID 為 Identity 列)
例 1
SELECT ACCT_ID
FROM FINAL TABLE
(INSERT INTO UID1.ACCOUNT (NAME, TYPE, BALANCE)
VALUES ('Master Card', 'Credit', 50000) )
版本 8 中還可以更改其他一些值,例如:
CACHE/NO CACHE
CYCLE/NO CYCLE
MINVALUE
MAXVALUE
INCREMENT BY
RESTART WITH
這些執行更改的功能,特別是 RESTART WITH,給 Identity 列的使用帶來了更大的靈活性。然而,這些功能是定義在單個表上的,這一本質使它們仍然受到了一些限制,而且應用程序對它們的利用也仍然有限。此外,這些更改還將導致表空間被置於 REORG 暫掛狀態,從而導致表無法獲得表空間。
![]() ![]() |
![]() |
在首次宣布 Sequence 對象時,我認為它們只是為了將應用程序從其他數據庫移植到 DB2 而向 DB2 添加的另一功能。但是我越是深入地研究它們,就越是開始喜歡這些新的對象了,因為它們消除了我們對於 Identity 列的許多限制,而且它們還具有許多獨特且有用的功能。它還向我們提供了數字生成的另一備選方法。
Sequence 對象是用戶定義的對象,用以根據其創建規范生成數值序列。 它們提供一個由 DB2 生成的增量計數器,並且與 Identity 列十分相似。可將 Identity 列當作一種特殊的 Sequence 對象;但是,sequence 列與表是分開的。
Sequence 對象值可因為各種理由而用於應用程序中。這樣做有一些好處,例如:
- 無需等待值的增加;
- 獨立的連續數字生成對象(不與表關聯);
- 遞增或遞減地生成數字;
- 用於從其他數據庫移植應用程序;
- 可以生成鍵,用以跨多個表(RI 或相關的應用程序)協調各鍵。
序列名由兩部分組成:128 字節的模式名和 128 字節的標識符。它們是通過新的 CREATE SEQUENCE 語句創建的,並且其所有屬性完全都是由用戶定義的(您也可以使用默認值)。Sequence 對象中的值可以是任何數字數據類型。初值是用 START WITH 值定義的,而增量則是由 INCREMENT BY(遞增的或遞減的)定義的。可以緩存這些值或按請求次序來生成。
下面這個例子展示了一個 Sequence 對象的創建及其簡單用法。
CREATE SEQUENCE ACCOUNT_SEQ
AS INTEGER
START WITH 1
INCREMENT BY 10
CYCLE
CACHE 20
正如您所看到的,Sequence 對象的使用方法與許多人對於 Identity 列的使用比較相似。但是這更為有效,而且 Sequence 對象有一些極佳的使用優點。例如可以使用 NEXT VALUE FOR 和 PREVIOUS VALUE FOR。NEXTVALUE FOR 將為 Sequence 對象生成並返回下一值。而 PREVIOUS VALUE FOR 將為 Sequence 對象生成並返回前一值。這些語句可用於下列地方:
- SELECT 和 SELECT INTO 語句;
- INSERT 語句里面的 fullselect 的 SELECT 從句;
- UPDATE 語句里面的 SET 從句(搜索或定位);
- SET 主變量;
- VALUES 或 VALUES INTO;
- CREATE PROCEDURE、FUNCTION、TRIGGER。
下面的例子(右邊的表 2)展示了這些語句的用法:
假定 ACCT_SEQ 為 START WITH 10 INCREMENT BY 10
正如您所看到的,使用 Sequence 對象代替 Identity 列有許多好處。下面是兩者的一個簡單比較。
Sequence 對象與 Identity 列 | |
Sequence 對象 | Identity 列(帶有 V8 功能) |
單獨的 Sequence 對象是在用戶請求時創建的 | 由 DB2 生成/維護和填充的內部 Sequence 對象 |
可用於它們所選擇的任何目的,並且存在有多個 | 與特定的表相關聯,並且只能有一個 |
循環(CYCLE)將回繞和重復,並且無需進行惟一性考慮 | 如果惟一索引在 Identity 列上並且創建了復制,那么循環(CYCLE)可能會產生問題 |
當用於填充表時,后來可被更新 | 如果是 GENERATED ALWAYS,就無法被更新 |
可以更改(ALTER)Sequence 對象的屬性。 還可以進行注釋(COMMENT)以及授予/撤銷(GRANT/REVOKE)權限 |
只能更改表(ALTER TABLE)(如果向已填充的表添加 Identity 列,將被置於 REORG 暫掛狀態) |
可被刪除 | 不能從表中刪除* |
支持 NEXT VALUE FOR EXPRESSION 和 PREVIOUS VALUE FOR EXPRESSION | 必須使用 ID_VAL_LOCAL 並且只返回用戶提交(commit)范圍內的最后值 |
* 如果今后設計中使用 Sequence 對象比使用 Identity 列更好,那么在選擇 Identity 列時就要考慮仔細。如果它們是在已填充的表上定義的並且需要被刪除,那么必須刪除表然后重新創建。這對於高效環境中的大型表可能是一個大問題。 |
![]() ![]() |
![]() |
Identity 列和 Sequence 對象在我們的設計中都占有一席之地。鑒於它們都可以達到相同的目的 —— 生成序號,所以應該由您來選擇哪一個更適合您。這將取決於您對生成的數字所需的靈活性,以及應用程序將如何使用這些數字。