序列作為主鍵使用的原理 優缺點討論

2021-09-22 16:58:56 字數 2464 閱讀 4222

這幾天和同事一直在討論關於表設計中主鍵選擇的問題,用sequence作為主鍵究竟有什麼好處,又有什麼缺點,尤其是有些事務場景上下文需要用到建立的序列值,如何用?其實我想說的是,可能只是乙個很簡單的概念,可能深入理解,還是有很多未知的知識,當然也就可能會有一些容易忽略但又可能很關鍵的坑,只有碰了才知道。。。

以下是總結摘要,如有疏漏,還請過路的各位大俠賜教。

1、首先說下seq.nextval主要有以下兩種使用場景:

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

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

2、其次可以簡單說下呼叫序列的原理,只有理解了序列的原理,才能有助於我們知道如何正確使用序列。

使用序列時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$表有頻繁的更新操作,日誌量會增加,尤其在rac下,更新該行的時候,該資料塊會在節點間不停的傳送,就會產生可能的爭用,這種問題會被放大。因此為了減少這種情況,我們可以將cache快取值設定大一些,例如1000,減少對字典表的更新。

序列還有乙個問題,就是cache快取是例項級的,對於rac,比如第乙個節點使用序列時會分配1-20,第二個節點會被分配21-40,oracle保證不會重複,但若節點crash了,比如節點1壞了,那麼序列就會出現斷號,節點1再次使用時,只會從41-60,由於我們用主鍵只為了標示唯一,不關心段號,也不關心產生的順序,所以這些可以忽略。

:最近在討論某系統和乙個外系統做全域性事務的事情,本想用這個主鍵作為兩系統傳輸的一部分,用於控制全域性事務,且用其作為判斷交易先後順序的依據,這是不太符合要求的,因為是rac,序列是基於例項級cache,那麼如果不能保證某一型別的交易總在乙個節點上執行,那麼不同次交易產生的主鍵序列值可能不是遞增的,例如節點1處理一次交易,產生序列是1,節點2處理一次交易,產生序列是21,此時節點1再處理一次交易,產生序列是2;除非設定序列為order,但這樣在rac就有可能產生資源爭用的問題,因為為了保證多節點間每次產生的序列值是遞增的,每次產生就需要多節點間判斷當前值後,才能知道下乙個值是多少,而且會有額外的鎖,保證同一時間只有乙個節點在做這個操作,當然究竟是否會產生資源爭用,還是要依據實際的業務併發量,或者壓力測試才能證明,這裡只是說可能會這樣的問題,不是一定會,否則oracle就不會有提供這種order的建立屬性,凡事不絕對。

3、結合(1)的場景,

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

> 這個場景下,如果序列cache設定為1000,呼叫100次nextval幾乎沒有影響。

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

> 這個場景,就有些說的了。如果是同一事務中需要用到之前的序列值,那麼就需要提前用select seq.nextval from dual儲存到變數中,(當然,如果是用plsql語句,則可以不用提前儲存變數這步,但咱們的應用中不適用,就不多說了)。

有意思的兩個值作為主鍵

有乙個表,需要兩個欄位date和platform作為主鍵。於是我把這兩個字段封裝成乙個物件,並重寫等於 小於運算子或hash值 實際沒有重寫成功,用的是python 才能夠將物件作為dict 字典 的key。剛接觸python,沒能實現我想要的 冥思苦想之際,得人指點 廢那勁幹嘛,直接把這兩個值用字...

使用GUID作為資料表主鍵的好處

資料表主健通常採用以下三種方式 1.自動遞增值。2.唯一名稱。這個是使用自己定義的演算法來生成乙個唯一序列號。3.guid 全域性唯一識別符號 在客戶端生成,由 guid 的特性決定,通過 guid 生成的值可能出現重複的機會幾乎等於零,因此保證在插入表的時候主鍵值唯一。可以方便處理分布式資料的提交...

使用GUID作為資料庫主鍵的測試

今天聽了msdn的webcast,是關於entlib的資料訪問的講座,末尾我問了兩個自己所關心的問題 在乙個較大型的應用中,如果需要用到兩套以上的資料庫 如 sql server和oracle 是否可以把需要的sql查詢全部封裝在儲存過程裡,這樣就只需要一套訪問 了,有沒有更好的方法解決這個問題?在...