自增長的聚集鍵值不會擴充套件(scale)

2021-09-22 07:00:33 字數 3000 閱讀 7308

如何選擇聚集鍵值的最佳實踐是什麼?乙個好的聚集鍵值應該有下列屬性:

我們來具體看下所有這3個屬性,還有在sql server裡為什麼自增長值實際上是不會擴充套件的。

聚集鍵值應該i越小越好。為什麼?因為它要占用空間,聚集鍵值也在每個非聚集索引的葉子曾作為邏輯指標。如果你的聚集鍵值很廣,你的非聚集索引也會很大。如果你定義了非唯一非聚集索引(non-unique non-clustered index)(基本上是這個情況),聚集鍵也是你非聚集索引導航結構的一部分。因此你的索引會變得很大。我們的目標是最小化我們的索引。因為我們要為此承擔更多的物理儲存,快取池,這些都是sql server從儲存快取讀取的索引頁的地方。

一般我們會選擇技術性鍵值(technical key value)(像int/bigint資料型別),而不是自然鍵值(natural key value)。當我也看到很多長度有100 bytes甚至更長的聚集鍵值(包含lastname, firstname, socialsecuritynumber等)。相信我——你這是在浪費記憶體!沒有必要這樣做。選擇乙個技術性鍵值就可以了。

因為聚集鍵值在每個非聚集索引裡都會複製乙份,你的聚集鍵值應該從不改變!不然sql server需要經常維護,去更新執行計畫裡每個在你表上定義的非聚集索引。你再次引入了你不需要的額外計算。把你的cpu用在其它重要的事情上。我們都知道,自然鍵值是會改變的(例如lastname列,當你結婚了就會改變)。

技術性鍵值(像int identity)不會改變(預設)。因此在你非聚集索引裡的邏輯指標(聚集鍵值格式)保持穩定——永遠沒有必要修改他們!

「好」的聚集鍵值第3個重要屬性是選擇列應該給你自增長的值。為什麼?因為你總是在你聚集索引的末尾增加額外記錄,因此你可以避免昂貴的分頁(page splits)(涉及到cpu週期,事務日誌等問題)和索引碎片。使用像int identity自增長值列,在99%的情況下是沒有問題的,但還是有些情形,這個方法會導致嚴重的擴充套件性問題。假設你有個工作量,那裡有很多不同使用者用自增長聚集鍵值對同個表永久插入鍵值。想下日誌/審計表(logging/auditing table)

我們來仔細看下當你在記憶體裡讀寫頁時,在sql server內部會發生什麼。當sql server訪問特定記憶體機構(像儲存在快取池裡的頁)時,這些記憶體訪問必須被多個執行緒上同步。你不能在記憶體裡併發寫入同個頁。當乙個執行緒寫入乙個頁時,其他一些執行緒同時就不能讀這個頁。另外併發程式設計你用互斥器(mutexes),每次當你寫乙個頁,工作執行緒需要獲得排它閂鎖(exclusive latch(ex))。而且這些閂鎖彼此是不相容的。

當你進行insert語句時,工作執行緒在insert語句發生的頁獲得排它閂鎖。同時沒有執行緒可以從這個頁讀寫。使用自增長聚集鍵值這個方法實際上不會擴充套件,因為你在你聚集索引的末尾插入你的記錄。因此你的並行執行緒/查詢在你聚集索引裡同個最後頁為閂鎖競爭。作為乙個***sql server會連續執行你的insert語句——乙個接著乙個insert,你就碰到了著名的最後頁插入閂鎖競爭(last page insert latch contention)。我們來看下面的。

用自增長聚集鍵值的最佳實踐,在聚集鍵的末尾你有乙個熱區。你的記錄越小,這裡就會有更多的競爭。如果解決那個問題?簡單:把你的insert語句擴散到聚集索引的整個b樹結果。有很多方法可以實現這個:

1

create

function

bitreverse2(

3@input

bigint4)

5returns

bigint6as

7begin

8declare

@workvalue

bigint

=@input

9declare

@result

bigint=0

;10declare

@counter

int=0;

11while

@counter

<

6312

begin

13set

@result

=@result*2

14if (@workvalue

&1)=115

begin

16set

@result

=@result+1

17set

@workvalue

=@workvalue-1

18end

19set

@workvalue

=@workvalue/2

20set

@counter

=@counter+1

21end

2223

return

@result

2425

end

使用像int identity資料型別的範圍小,靜態的,自增長的聚集鍵值99%的情況都沒問題。但在一些有大量併發insert語句的情況(日誌/審計表(logging/auditing table)),用那個方法你會碰到最後也插入閂鎖競爭(last page insert latch contention)。如果你碰到這個特定問題,你就會離開這99%的太平區域,你要保證insert語句散布到你的整個b樹結構。基本上你就在如果將多執行緒散步到典型b樹結構做鬥爭。

希望這篇文章可以幫助你從內部理解:為什麼自增長聚集鍵值會傷及你表的擴充套件性。

自增長的聚集鍵值不會擴充套件(scale)

如何選擇聚集鍵值的最佳實踐是什麼?乙個好的聚集鍵值應該有下列屬性 我們來具體看下所有這3個屬性,還有在sql server裡為什麼自增長值實際上是不會擴充套件的。聚集鍵值應該i越小越好。為什麼?因為它要占用空間,聚集鍵值也在每個非聚集索引的葉子曾作為邏輯指標。如果你的聚集鍵值很廣,你的非聚集索引也會...

自增長的聚集鍵值不會擴充套件(scale)

如何選擇聚集鍵值的最佳實踐是什麼?乙個好的聚集鍵值應該有下列屬性 我們來具體看下所有這3個屬性,還有在sql server裡為什麼自增長值實際上是不會擴充套件的。聚集鍵值應該i越小越好。為什麼?因為它要占用空間,聚集鍵值也在每個非聚集索引的葉子曾作為邏輯指標。如果你的聚集鍵值很廣,你的非聚集索引也會...

mysql 去除列的自增長 mysql自增長列

自增長列必須是索引列,否則無法建立成功表,對myisma和innodb都一樣 localhost testdb root create table test5 id int auto increment,name varchar 10 engine innodb error 1075 42000 l...