學習:關於oracle序列(sequence)組成的主鍵和唯一的字符串組成的主鍵在性能上如何?


對oracle了解還很初級皮毛,希望通過這里能伴隨自己在數據庫方面慢慢的成長!也希望在這里能多多認識一些數據庫方面的朋友,一起學習,互相交流。

最近要學習oracle里面可以起到自增長唯一標識作用的sequence序列和其他方式組成的唯一標識主鍵在性能上差異如何。

向身邊一些朋友了解了一下,說是sequence序列組成主鍵是數值型的肯定比用字符串方式組成的唯一標識查詢快,因為查詢數值型比字符串型快。

為此,最近網上查詢了一些這方面的一些資料,貼到這里做個學習筆記,方便自己日后總結整理:

從網上查閱的一些資料來看有兩種方法可以設置主鍵,一種是自增長主鍵,另一種就是生成唯一序列。

一、自增長主鍵

--首先建一個表TEST

create table TEST
(
  NID int PRIMARY KEY,
  test1 varchar2(20),
  test2 varchar2(20),
  test3 varchar2(20),
  test4 varchar2(20),
  test5 varchar2(20)
)

-- 再建一個序列SEQ_TEST
create sequence SEQ_TEST
minvalue 1        --最小值
nomaxvalue        --不設置最大值
start with 1      --從1開始計數
increment by 1    --每次加1個
nocycle           --一直累加,不循環
nocache;          --不建緩沖區

以上代碼完成了一個序列(sequence)的建立過程,名稱為SEQ_TEST,范圍是從1開始到無限大(無限大的程度是由你機器決定的),nocycle 是決定不循環,如果你設置了最大值那么你可以用cycle 會使seq到最大之后循環.對於nocache順便說一下如果你給出了cache值那么系統將自動讀取你的cache值大小個seq,這樣在反復操作時會加快運行速度,但如果遭遇意外情況如當機了或oracle死了,則下次取出的seq值將和上次的不連貫.(如果連不連貫無所謂建議用cache,因為時間就是金錢呀!)
你只有了表和序列還不夠,最好再建一個觸發器來執行它!代碼如下:

CREATE OR REPLACE TRIGGER tg_test 
BEFORE INSERT ON test FOR EACH ROW WHEN (new.nid is null)
begin
select seq_test.nextval into:new.nid from dual;
end;

 

下面是測試

select * from test
insert into test(nid,test1) values(6,'aaa')
insert into test(test1) values('bbb') 

二、唯一序列

        SYS_GUID() 生成32位的唯一編碼。

        序列生成器所生成的數字只能保證在單個實例里是唯一的,這就不適合將它用作並行或者遠程環境里的主關鍵字,因為各自環境里的序列可能會生成相同的數字,從而導致沖突的發生。SYS_GUID會保證它創建的標識符在每個數據庫里都是唯一的。
  此外,序列必須是DML陳述式的一部分,因此它需要一個到數據庫的往返過程(否則它就不能保證其值是唯一的)。SYS_GUID源自不需要對數據庫進行訪問的時間戳和機器標識符,這就節省了查詢的消耗。

        很多應用程序都依靠序列生成器來創建數據行的主關鍵字,這些數據行沒有一個明顯的主值,這也就是說,在這樣的數據集里一條記錄的創建就會讓數據列發生改變。因此,管理員可能會對在表格中將SYS_GUID用作主關鍵字而不使用序列數感興趣。這在對象在不同機器的不同數據庫里生成以及需要在后來合並到一起的情況下很有用。

        使用SYS_GUID或者序列會在數據庫使用周期里的某些地方造成性能上的消耗;問題就是在哪里。對於SYS_GUID而言,性能上的影響在查詢時間和創建時間上(在表格里要創建更多的塊和索引以容納數據)。對序列而言,性能上的影響在查詢期間,在這個時候,SGA序列的緩沖區被用光。在缺省情況下,一個序列一次會緩沖20個值。如果數據庫沒有使用這些值就關閉了,它們就會被丟失。

        SYS_GUID生成的值的另一個顯著的不足之處是,管理這些值會變得困難得多。你必須(手動)輸入它們或者通過腳本來填充它們,或者將它們作為Web參數來傳遞。出於這些原因,將SYS_GUID作為一個主關鍵字不是一個很好主意,除非是在一個並行的環境里或者希望避免使用管理序列生成器的情況下。

網上查了sys_guid()函數的概念,如下:

SYS_GUID (),是Oracle 8i 后提供的函數。SYS_GUID產生並返回一個全球唯一的標識符(原始值)由16個字節組成。在大多數平台,生成的標識符由主機標符,執行函數的進程或者線程標識符,和進程或線程的一個非重復的值(字節序列)組成。

sys_guid()和傳統的序列(sequence)

  Oracle8i引入了SYS_GUID這個概念,它同Oracle管理員所使用的傳統的序列(sequence)相比具有諸多優勢。一個序列生成器只是簡單地創建從給定的起點開始的一系列整數值,而且它被用在選擇陳述式的時候自動地遞增該系列。 
 
  序列生成器所生成的數字只能保證在單個實例里是唯一的,這就不適合將它用作並行或者遠程環境里的主關鍵字,因為各自環境里的序列可能會生成相同的數字,從而導致沖突的發生。SYS_GUID會保證它創建的標識符在每個數據庫里都是唯一的。
 
  序列必須是DML陳述式的一部分,因此它需要一個到數據庫的往返過程(否則它就不能保證其值是唯一的)。SYS_GUID源自不需要對數據庫進行訪問的時間戳和機器標識符,這就節省了查詢的消耗。 
 
  很多應用程序都依靠序列生成器來創建數據行的主關鍵字,這些數據行沒有一個明顯的主值,這也就是說,在這樣的數據集里一條記錄的創建就會讓數據列發生改變。因此,管理員可能會對在表格中將SYS_GUID用作主關鍵字而不使用序列數感興趣。這在對象在不同機器的不同數據庫里生成以及需要在后來合並到一起的情況下很有用。
 
  但是,SYS_GUID所生成的值是一個16個字節的原始值。序列所生成的整數不會使用16字節(的值),除非它達到了10的30次方(每個字節兩個16進制顯示位),而且數字是相當獨特的:
 
  SQL> select dump(123456789012345678901234567890) from dual;
 
  DUMP(123456789012345678901234567890)
 
  --------------------------------------------------------------
 
  Typ=2 Len=16: 207,13,35,57,79,91,13,35,57,79,91,13,35,57,79,91
 
  使用SYS_GUID或者序列會在數據庫使用周期里的某些地方造成性能上的消耗;問題就是在那里。對於SYS_GUID而言,性能上的影響在查詢時間和創建時間上(在表格里要創建更多的塊和索引以容納數據)。對序列而言,性能上的影響在查詢期間,在這個時候,SGA序列的緩沖區被用光。在缺省情況下,一個序列一次會緩沖20個值。如果數據庫沒有使用這些值就關閉了,它們就會被丟失。 
 
  SYS_GUID生成的值的另一個顯著的不足之處是,管理這些值會變得困難得多。你必須(手動)輸入它們或者通過腳本來填充它們,或者將它們作為Web參數來傳遞。
 

性能比較

  創建下列對象:
 
  create table tsg as select RAWTOHEX(sys_guid()) sgid,a.* from all_objects a;
 
  create SEQUENCE seq_tsg;
 
  create table tsg2 as select seq_tsg.nextval,a.* from all_objects a;

空間比較

  現在這兩個表:tsg和tsg2擁有的行數相同,但大小不同:
 
  
行數 Number Extents Size in bytes 索引大小
TSG(SYS_GUID主鍵) 50231 23 8388608 3145728
TSG2(Sequence主鍵) 50231 21 6291456 917504
 換言之,相同條件下,使用SYS_GUID做主鍵比用Sequence做主鍵,表多消耗了空間2097152 byte,索引多消耗2228224 byte,平均每行多消耗86.1 byte.
 
  考慮到生產環境下,每天5萬條記錄,則一年365*50000=18250000條記錄,則理論上需要多耗費空間約合 1.43GB 存儲空間.這些空間對磁盤消耗而言可以忽略不計,對內存仍然是有一定影響的,但就當前的服務器能力而言,影響有限,如果對表進行合理分區后,這種影響可以降低至極低。

執行計划比較

  比較唯一查詢時的執行計划:
 
  對TSG執行:
 
  select owner
 
  from tsg
 
  where sgid = 'F36C09B7A7A84297995352D2409EB40E'
 
  對TSG2執行:
 
  select owner
 
  from tsg2
 
  where sgid = 99
 
  統計信息對比:從以上統計信息看,執行計划相同。
 
  可以預料到的是,由於使用SYS_GUID做主鍵,比較的是字符串,故耗費CPU要高些,因此,logical reads要高些,至於Physical Readers居然低一些,就不知道原因了(實際上二者基本都沒有產生大量的物理讀),估計是我的測試環境Db Cache太小的緣故.
 
  對於響應時間,這應該是計算機環境產生的影響,不能說明問題,這兩條語句響應都很快,小於0.02秒.

小結

  從實踐來看,使用SYS_GUID()做主鍵的優點多於負面影響。特別是在多個數據庫數據集成時,GUID的優點顯而易見.A項目最終沒有采用客戶定義的“貨單唯一序號”作為主鍵,也是出於關系數據庫設計的法則約定:“主鍵不要代表任何意義”。
 
自我小結:
從以上找的這些資料來看,覺得是選用sequence做主鍵還是唯一編碼做主鍵各有利弊,sys_guid ()生成的序列號過長,這會消耗數據庫存儲空間,且管理不方便。但是對數據集成和並行環境的應用數據的唯一性比sequence好,減少沖突發生。那是不是可以通過什么辦法產生位數比較短的唯一序號就解決了guid產生的問了就好了呢?不知道還有沒有更好的標識辦法,希望這方面有研究的朋友給一些指點,回頭有空自己參照網上的舉例也再親自做一些簡單的試驗驗證一下。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM