国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > 綜合 > 正文

自增長的聚集鍵值不會擴展(scale)

2024-07-21 02:46:23
字體:
供稿:網(wǎng)友
自增長的聚集鍵值不會擴展(scale)

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

  • 范圍小的(Narrow)
  • 靜態(tài)的(Static)
  • 自增長的(Ever Increasing)

我們來具體看下所有這3個屬性,還有在SQL Server里為什么自增長值實際上是不會擴展的。

范圍小的(Narrow)

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

一般我們會選擇技術(shù)性鍵值(technical key value)(像INT/BIGINT數(shù)據(jù)類型),而不是自然鍵值(natural key value)。當我也看到很多長度有100 bytes甚至更長的聚集鍵值(包含LastName, FirstName, SocialSecurityNumber等)。相信我——你這是在浪費內(nèi)存!沒有必要這樣做。選擇一個技術(shù)性鍵值就可以了。

靜態(tài)的(Static)

因為聚集鍵值在每個非聚集索引里都會復制一份,你的聚集鍵值應該從不改變!不然SQL Server需要經(jīng)常維護,去更新執(zhí)行計劃里每個在你表上定義的非聚集索引。你再次引入了你不需要的額外計算。把你的CPU用在其它重要的事情上。我們都知道,自然鍵值是會改變的(例如LastName列,當你結(jié)婚了就會改變)。

技術(shù)性鍵值(像INT IDENTITY)不會改變(默認)。因此在你非聚集索引里的邏輯指針(聚集鍵值格式)保持穩(wěn)定——永遠沒有必要修改他們!

自增長的(Ever Increasing)

“好”的聚集鍵值第3個重要屬性是選擇列應該給你自增長的值。為什么?因為你總是在你聚集索引的末尾增加額外記錄,因此你可以避免昂貴的分頁(Page Splits)(涉及到CPU周期,事務日志等問題)和索引碎片。使用像INT IDENTITY自增長值列,在99%的情況下是沒有問題的,但還是有些情形,這個方法會導致嚴重的擴展性問題。假設(shè)你有個工作量,那里有很多不同用戶用自增長聚集鍵值對同個表永久插入鍵值。想下日志/審計表(Logging/Auditing Table)

我們來仔細看下當你在內(nèi)存里讀寫頁時,在SQL Server內(nèi)部會發(fā)生什么。當SQL Server訪問特定內(nèi)存機構(gòu)(像存儲在緩存池里的頁)時,這些內(nèi)存訪問必須被多個線程上同步。你不能在內(nèi)存里并發(fā)寫入同個頁。當一個線程寫入一個頁時,其他一些線程同時就不能讀這個頁。另外并發(fā)編程你用互斥器(Mutexes)解決那個問題——像臨界區(qū)(Critical Section)。一些代碼路徑是人為互斥的。閂鎖(latches)用來在線程/查詢間的同步。每次當你讀一個頁,工作線程需要獲得共享鎖(Shared Latch(SH)),每次當你寫一個頁,工作線程需要獲得排它閂鎖(Exclusive Latch(EX))。而且這些閂鎖彼此是不兼容的。

當你進行INSERT語句時,工作線程在INSERT語句發(fā)生的頁獲得排它閂鎖。同時沒有線程可以從這個頁讀寫。使用自增長聚集鍵值這個方法實際上不會擴展,因為你在你聚集索引的末尾插入你的記錄。因此你的并行線程/查詢在你聚集索引里同個最后頁為閂鎖競爭。作為一個副作用SQL Server會連續(xù)執(zhí)行你的INSERT語句——一個接著一個INSERT,你就碰到了著名的最后頁插入閂鎖競爭(Last Page Insert Latch Contention)。我們來看下面的圖片。

Last Page Insert

用自增長聚集鍵值的最佳實踐,在聚集鍵的末尾你有一個熱區(qū)。你的記錄越小,這里就會有更多的競爭。如果解決那個問題?簡單:把你的INSERT語句擴散到聚集索引的整個B樹結(jié)果。有很多方法可以實現(xiàn)這個:

  • 使用隨機聚集鍵值(像UNIQUEIDENTIFIER)。但要意識到副作用:在每個非聚集索引里邏輯指針更大,頁分裂問題……
  • 實現(xiàn)哈希分區(qū)(Hash Partitioning),如果你使用企業(yè)版本的SQL Server。
  • 使用SQL Server 2014里內(nèi)不能優(yōu)化表OLTP來剔除閂鎖。
  • 使用逆向索引(Reverse index),很遺憾SQL Server并不提供你像Oracle那樣的內(nèi)建索引。你也可以自己寫一個的……
 1 CREATE FUNCTION BitReverse 2 ( 3     @Input bigint 4 ) 5 RETURNS bigint 6 AS 7 BEGIN 8     DECLARE @WorkValue bigint=@Input 9     DECLARE @Result bigint=0;10     DECLARE @Counter int=0;11     WHILE @Counter<6312     BEGIN13         SET @Result=@Result*214         IF (@WorkValue&1)=115         BEGIN16             SET @Result=@Result+117             SET @WorkValue=@WorkValue-118         END19         SET @WorkValue=@WorkValue/220         SET @Counter=@Counter+121     END22     23     RETURN @Result24     25 END
小結(jié)

使用像INT IDENTITY數(shù)據(jù)類型的范圍小,靜態(tài)的,自增長的聚集鍵值99%的情況都沒問題。但在一些有大量并發(fā)INSERT語句的情況(日志/審計表(Logging/Auditing Table)),用那個方法你會碰到最后也插入閂鎖競爭(Last Page Insert Latch Contention)。如果你碰到這個特定問題,你就會離開這99%的太平區(qū)域,你要保證INSERT語句散布到你的整個B樹結(jié)構(gòu)。基本上你就在如果將多線程散步到典型B樹結(jié)構(gòu)做斗爭。

希望這篇文章可以幫助你從內(nèi)部理解:為什么自增長聚集鍵值會傷及你表的擴展性。

感謝關(guān)注。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 马鞍山市| 思南县| 广平县| 鄯善县| 漠河县| 行唐县| 苏尼特右旗| 郴州市| 泽州县| 永新县| 聂拉木县| 巴中市| 平舆县| 临沂市| 象山县| 梁平县| 冀州市| 呼和浩特市| 明星| 乃东县| 宣汉县| 宜春市| 日喀则市| 邻水| 札达县| 盘山县| 泉州市| 开远市| 宜良县| 海淀区| 博罗县| 阜南县| 福清市| 肇州县| 锡林郭勒盟| 沭阳县| 邯郸市| 梁山县| 临漳县| 历史| 尖扎县|