摘要:SQL Server 2005 - 如何精確估算資料庫的大小
筆者於「SQL Server 2005 完全實戰」 一書的第三章說明如何建立資料庫時就特別強調,儘可能以一個最大的大小作為資料庫的起始大小,並將資料庫設定成可自動膨脹,但是限制它最大能膨脹至多大以 便能預留一些磁碟空間。此作法的最大好處,就是不僅能在新增至資料庫的資料量比預期來得多時資料庫會自動加大,也不會發生磁碟空間不足的情形,爾後當資料 庫的空間還是不夠時,只需替資料庫增加次要資料檔與檔案群組即可。而且由於我們已儘可能以一個最大的大小作為資料庫的起始大小,可避免資料庫動不動就需要 膨脹,畢竟膨脹的頻率過高只會降低系統執行的效率。
很顯然的,精確預估資料庫的大小是非常重要的,除了上述好處外,也可以幫助您決定該選用容量多大的硬碟以及該將哪一個資料庫存放在哪一個硬碟上,比方說,您可以將資料量大且存取頻率高的資料庫儲存在速度較快的硬碟以獲取較佳的效率。
正如您所知道的,資料庫是由各種資料庫物件所組成,因此若想估算資料庫的大小,應從估算各個資料庫物件的大小開始。不過相信大家應該瞭解,決定資料庫大小最主要的因素其實是資料列(Data Row)的多寡,而資料列正是存放於資料庫內的資料表(Table)中,因此若想精確預估資料庫的大小,必須從估算資料庫中每一個資料表的大小開始。另外一項會隨著資料列之多寡而決定其存放空間大小的資料庫物件就是索引,而索引又區分為叢集索引與非叢集索引,因此估算資料庫大小的另外一項重要工作就是估算叢集索引與非叢集索引的大小。
說穿了,估算資料庫大小的重點在於估算資料表與索引的大小,其他資料庫物件不可能大到哪裡去,因此很容易自行預估。不過您別忘了,資料庫可能內含很多個資料表,而每一個資料表又能夠擁有一個叢集索引與多個非叢集索引,因此若想精確地估算出,必須一個一個去預估他們的大小。
大家別忘了!資料庫是由資料檔與記錄檔所組成,估算資料表與索引的大小僅代表您預估了資料檔的大小,您應該也要估算記錄檔的大小。因此整體而言,您必須如下所示去估算一個資料庫的大小:
資料庫的大小 =
(沒有叢集索引資料表1的大小 +
非叢集索引資料表1的大小 + 叢集索引資料表1的大小)+
(沒有叢集索引資料表2的大小 +
非叢集索引資料表2的大小+ 叢集索引資料表2的大小)+
˙˙˙
˙˙˙
(沒有叢集索引資料表N的大小 +
非叢集索引資料表N的大小+ 叢集索引資料表N的大小)+
記錄檔的大小
估算一個沒有叢集索引資料表的大小
首先我們討論如何估算沒有叢集索引之資料表的大小,請依下列步驟進行:
附註:
如果您對資料表不甚瞭解,請參閱「SQL Server 2005 完全實戰」一書第五章的說明。
1. 決定資料表大小的第一個要素,就是它擁有多少個欄位以及這些欄位的資料型別。圖表 1 詳列出 SQL Server 各種資料型別的大小,至於使用者自訂資料型別的大小,則必須去加總它的各個組成部分。算出資料表有多少個欄位以及這些欄位的大小,便能計算出每一筆資料列的大小。
不過從圖表1可以看出,事情似乎不如想像中的單純,因為我們必須考慮到固定長度的欄位與變動長度的欄位兩種類型。比方說,資料型別為 char 的欄位,其大小係由設計者所指定的欄位長度而定,也就是它的大小是固定且可精確計算的;但是資料型別為 varchar 的欄位,其大小則是由實際存放在欄位中之資料的大小而定,因此其大小是變動且只能約略估算的。
基本上,您必須遵循下列規則來計算出固定長度與變動長度之欄位的大小:
Ø 如果資料表擁有固定長度的欄位,則每一筆資料列必須預留一個「虛無位元映射」的空間來管理欄位能否存放NULL值,此空間的大小可依下列公式計算出來:
Null_Bitmap = 2 + (( Num_Cols + 7 ) / 8 )
Null_Bitmap:虛無位元映射空間的大小
Num_Cols:資料表所擁有之欄位的數目(固定長度與變動長度的欄位皆計算在內)
透過上列公式計算出來的結果如果有小數的部分,此時請去掉小數部分,因為我們只需要整數的部分。
Ø 由於我們實在很難去估算使用者到底會存放多少資料於變動長度的欄位中(廢話!如果可以預估就不會使用變動長度的資料型別了),為求保險,我們只好以變動長度欄位完全被填滿的狀況來計算。在此原則下,您可以使用下列公式來計算它們所需的空間:
Variable_Data_Size =
2+(Num_Variable_Cols × 2)+Max_Var_Size
Variable_Data_Size:所有變動長度欄位的總大小
Num_Variable_Cols:變動長度之欄位的數目
Max_Var_Size:各個變動長度欄位之最大大小的總和
上述公式中的Max_Var_Size係假設每一個變動長度的欄位都百分之百被填滿,如果您能夠預估本身之變動長度欄位被填滿的比例,請自行調整上述公式,以便更精確地計算出資料表的大小。
當然,如果資料表沒有任何變動長度的欄位,請將Variable_Data_Size設定成 0。
資料型別 | 大小(單位:Byte) |
char | 由您所指定的欄位長度而定 |
varchar | 由實際存放在欄位中之資料的大小而定 |
varchar(max) | 實際存放在欄位中之資料大小再加2個Bytes |
nchar | 您所指定之欄位長度的兩倍大 |
nvarchar | 實際存放在欄位中之資料大小的兩倍大再加2個Bytes |
nvarchar(max) | 實際存放在欄位中之資料大小的兩倍大再加2個Bytes |
binary | 由您所指定的欄位長度而定 |
varbinary | 實際存放在欄位中之資料大小再加2個Bytes |
varbinary(max) | 實際存放在欄位中之資料大小再加2個Bytes |
bigint | 8 |
int | 4 |
smallint | 2 |
tinyint | 1 |
float,精確度1~7 | 4 |
float,精確度8~15 | 8 |
double precision | 8 |
real | 4 |
money | 8 |
smallmoney | 4 |
datetime | 8 |
smalldate | 4 |
bit | 1個bit |
text | 由實際存放在欄位中之資料的大小而定 |
ntext | 實際存放在欄位中之資料大小的兩倍大 |
image | 由實際存放在欄位中之資料的大小而定 |
timestamp | 8 |
decimal或numeric,精確度1~9 | 5 |
decimal或numeric,精確度10~19 | 9 |
decimal或numeric,精確度20~28 | 13 |
decimal或numeric,精確度29~38 | 17 |
sql_variant | 8016 個 Bytes |
uniqueidentifier | 128 |
xml | 最大可至 2 GB |
圖表 1
2. 您還要知道一件事,每一筆資料列的標頭大小是 4 個Bytes。至此,您可以採用下列公式計算出每一筆資料列的大小:
Row_Size =
Fixed_Data_Size+Variable_Data_Size+Null_Bitmap+4
Row_Size:每一筆資料列的大小
Fixed_Data_Size:各個固定長度之欄位大小的總和
3. 接下來,您必須依下列公式計算出每一個分頁(Page)會存放多少筆資料列(每一個分頁的剩餘空間是 8,096個Bytes):
Rows_Per_Page = ( 8096 ) / ( Row_Size + 2 )
Rows_Per_Page:平均每一個分頁的資料列個數
由於資料列並不會橫跨分頁存放,因此計算出之平均每一個分頁的資料列個數若出現小數,應將其無條件捨去,並取最接近的整數資料列。公式中要加上 2 這個值,乃是分頁位置陣列中該資料列的位置(Entry)。
附註:
筆者於 「SQL Server 2005 完全實戰」一書的第三章曾經說明,每一個分頁的大小是 8 K(或 8,192 Bytes),但是每一個分頁的前 96 個Bytes是標頭區,標頭區會存放一些系統資訊,包括:分頁的頁碼、分頁的類型、分頁中的剩餘空間、以及擁有此分頁之物件的 ID,因此剩餘空間自然是 8,096 個Bytes(8192 - 96 = 8096)。
4. 喔喔!請稍安勿躁!事情還沒結束呢?如果您打算要替資料表建立叢集索引,則必須根據指定的填滿因數(Fill Factor)來計算出每一個分頁的預留剩餘空間足夠存放多少筆記錄。計算公式如下所示:
Free_Rows_Per_Page =
8096 × (( 100 - Fill_Factor ) / 100 ) / Row_Size
Free_Rows_Per_Page:平均每一個分頁的剩餘空間足夠存放多少筆資料列
公式中的 Fill_Factor 用來指定填滿因數,此值是一個整數值而不是百分比。如果您沒有要建立任何叢集索引,請將 Fill_Factor 設定成 100。此外,由於資料列並不會橫跨分頁存放,因此若計算出的Free_Rows_Per_Page出現小數,應將其四捨五入。
5. 現在,要想知道欲儲存所有的資料列需要多少個分頁,使用下列公式即可計算出:
Num_Pages =
Num_Rows / ( Rows_Per_Page - Free_Rows_Per_Page )
Num_Pages:分頁的數目
Num_Rows:資料表所擁有之資料列的數目
於此一公式中,您必須自行去預估的,就是資料表所內含之資料列的數目,並且要將計算後之結果無條件進位成整數的分頁數目。我想,對於一位有經驗的使用者而言,這不會太困難,而對於那些要將系統升級至 SQL Server 的用戶而言,資料表擁有多少個資料列更是非常確定的。
6. 各位朋友恭喜您,現在大家終於可以使用下列公式估算出一個不具有任何索引之資料表的大小:(每一個分頁的大小是 8,192 個Bytes)
資料表的大小(單位:Bytes) = Num_Pages × 8192
附註:
在估算text、ntext、image、varchar(max)、nvarchar(max)、varbinary(max)與xml這幾種大型物件的大小時,都會以該大型物件大小的平均值來計算。
請各位讀者耐心看下去,後面兩節的資料表大小估算步驟比起本節所解說的步驟還要繁瑣多了。
估算一個非叢集索引資料表的大小
想估算一個資料表之各個非叢集索引的大小,必須先估算在非叢集索引之非分葉層級(Leaf Level)所能儲存索引的大小,然後再估算在非叢集索引的分葉層級中所能儲存索引的大小,再將這兩者的大小加總才是整個非叢集索引資料表的大小。
請依下列步驟來估算資料表在非叢集索引之非分葉層級所能儲存索引的大小:
1. 如果您的索引鍵值內含固定長度與變動長度的欄位,必須計算這些欄位於索引記錄中佔用多少空間。每一個欄位的大小取決其資料型別與長度,相關資訊請參閱圖表4-22。
2. 如果索引不是唯一的,就需要將資料列定位器(Locator)計算在內。當非叢集索引不是唯一時,資料列定位器會與非叢集索引會進行組合,以便為每列產生唯一的索引鍵。
如果非叢集索引是在資料表上,資料列定位器就是資料表的相關識別碼(RID),它是8位元組的大小。所以我們可以使用下列的公式:
Num_Key_Cols = Num_Key_Cols + 1
Num_Variable_Key_Cols = Num_Variable_Key_Cols + 1
Max_Var_Key_Size = Max_Var_Key_Size + 8
Num_Key_Cols:
索引鍵中的欄位數目(包含固定長度與變動長度的欄位)
Num_Variable_Key_Cols:索引鍵中變動長度欄位的數目
Max_Var_Key_Size:所有變動長度索引鍵欄位的最大總大小
如果非叢集索引是位於叢集索引上,那麼資料列定位器就是叢集索引鍵欄位。這些欄位必須與非叢集索引鍵結合,而這些欄位是位於叢集索引鍵中的資料欄位,但這些資料欄位並未存在於非叢集索引鍵資料欄位的集合中。這些欄位的空間大小,可依下列公式計算出來:
Num_Key_Cols = Num_Key_Cols +
不位於非叢集索引鍵資料欄位集合中的叢集索引鍵資料
欄位的數目(如果叢集索引不是唯一的,則 + 1)
Fixed_Key_Size = Fixed_Key_Size +
不位於非叢集索引鍵資料欄位集合中的固定長度叢集索引
資料欄位的總位元組大小
Num_Variable_Key_Cols = Num_Variable_Key_Cols +
不位於非叢集索引鍵資料欄位集合中的變動長度叢集索引鍵
資料欄位的數目(如果叢集索引不是唯一的,則 + 1)
Max_Var_Key_Size = Max_Var_Key_Size +
不位於非叢集索引鍵資料欄位集合中的變動長度叢集索引鍵
資料欄位的最大位元組大小(如果叢集索引不是唯一的,則 + 4)
Num_Key_Cols:
索引鍵值中的欄位數目(包含固定長度與變動長度的欄位)
Fixed_Key_Size:索引鍵值中固定長度欄位的數目
Num_Variable_Key_Cols:索引鍵值中變動長度欄位的數目
Max_Var_Key_Size:所有變動長度索引鍵欄位的最大總大小
3. 可以保留資料列的一部份,稱為「虛無位元映射」的空間,用來管理資料列的Null屬性。如果索引鍵有可為Null資料列的話,在上個步驟所提到的任何所需叢集索引鍵欄位,其中有一部份的索引鍵欄位將保留作為虛無位元映射之用。此空間的大小可依下列公式計算出來:
Index_Null_Bitmap = 2 + (( Num_Null_Key_Cols + 7 ) / 8)
Index_Null_Bitmap:索引虛無位元映射空間的大小
Num_Null_Key_Cols:可為Null的索引鍵資料欄位之個數
如果計算所得的 Index_Null_Bitmap 出現小數,請將小數捨去而只取整數的部分。如果沒有可為 Null 的索引鍵資料欄位時,也就是當 Num_Null_Key_Cols 個數為 0時,請直接將 Index_Null_Bitmap 設定為 0。
4. 如果索引鍵值內含變動長度的欄位,請採用下列公式計算出於索引記錄中需要多少空間來存放這些欄位:
Variable_Key_Size =
2 + ( Num_Variable_Key_Cols × 2 ) + Max_Var_Key_Size
Variable_Key_Size:變動長度欄位的總大小
Num_Variable_Key_Cols:索引鍵中變動長度欄位的數目
Max_Var_Key_Size:所有變動長度索引鍵欄位的最大總大小
如果索引鍵值中並未包含變動長度的欄位,請將Variable_Key_Size 設定成 0。
本公式係假設所有的變動長度鍵值欄位係百分之百被填滿,如果您的變動長度鍵值欄位並非百分之百被填滿,請自行於上述公式中,將 Max_Var_Key_Size 乘上填滿因數的百分比,以便更精確估算出索引的大小。
5. 至此,我們可以使用下列公式計算出索引列的大小:
Index_Row_Size = Fixed_Key_Size + Variable_Key_Size +
Index_Null_Bitmap + 1 + 6
Index_Row_Size:索引列的總大小
Fixed_Key_Size:所有固定長度索引鍵欄位的總大小
公式等號右側的數字 1 為索引列中標頭檔所佔用的大小,而數字 6 則為子分頁 ID 指標所佔用的大小。
6. 緊接著,我們可以使用下列公式計算出平均每一個分頁能夠存放多少筆索引列:
Index_Rows_Per_Page = ( 8096 ) / ( Index_Row_Size + 2 )
Index_Rows_Per_Page:平均每一個分頁能夠存放的索引列數目
由於索引列並不會橫跨分頁存放,因此計算出之平均每一個分頁的索引列數目若出現小數,應將其無條件捨去,並取最接近的整數索引列數目。公式中要加上 2 這個值,乃是分頁位置陣列中該資料列的位置(Entry)。
7. 現在要計算出在索引中包含多少層級,計算公式如下所示:
Levels =
1 + log Index_Rows_Per_Page ( Num_Rows / Index_Rows_Per_Page )
Levels:在索引中的層級數
Num_Rows:在資料表中的資料列數目
要注意的是,計算出來的索引層級數並不包含非叢集索引的分葉層級。
8. 請使用下列公式計算出位於索引中的分頁總數:
Num_Index_Pages = Σ Level ( Index_Rows_Per_Page ) Level - 1
Num_Index_Pages:索引中的分頁數目
1 <= Level <= Levels
舉個簡單的例子來說明上面公式的計算方法,假設在分葉層級的索引列總數是 1,000,平均每個分頁可以存放 10 個索引列,這也就是說,共需100個分頁來存放這 1,000 個索引列。在索引的下一個分葉要存放 100 個索引列,需要 10 個分頁。在往下一個分頁要存放 10 個索引列,因此只需要1個分頁。
光是看文字說明,我想大家還是不太懂,所以我們套入先前的公式,相信大家就可以瞭解了:
Levels = 1 + log 10 ( 1000 / 10 ) = 3
一共需要3層的分葉
Num_Index_Pages=( 10 ) 3 - 1 + ( 10 ) 2 - 1 + ( 10 ) 1 - 1 =111
因此,在索引中的分頁數目為 111。
9. 終於,我們可以使用下列公式計算出索引的大小:
索引的大小 = 8192 × Num_Index_Pages
不要忘記哦!每一個分頁的大小是 8,192 個 Bytes。
OK!您現在已經知道如何去估算資料表在非叢集索引非之分葉層級所能儲存索引的大小。現在我們要繼續討論另外一種狀況,就是當分葉層級是在非叢集索引的時候,要如何估算各個非叢集索引的大小,欲達此目的,需要使用先前估算出來的某些結果,並請依下列步驟進行:
1. 如果您的索引鍵內含固定長度與變動長度的欄位,必須計算這些欄位於索引記錄中的分葉層級佔用多少空間。每一個欄位的大小取決其資料型別與長度,相關資訊請參閱圖表 1。
如果非叢集索引不包含任何資料行的話,此時便需要套用先前估算出來的一些結果:
Num_Leaf_Cols = Num_Key_Cols
Fixed_Leaf_Size = Fixed_Key_Size
Num_Variable_Leaf_Cols = Num_Variable_Key_Cols
Max_Var_Leaf_Size =Max_Var_Key_Size
Num_Leaf_Cols:索引鍵中的分葉數目
Fixed_Leaf_Size:索引鍵中固定長度欄位的分葉數目
Num_Variable_Leaf_Cols:索引鍵中變動長度欄位的分葉數目
Max_Var_Leaf_Size:所有變動長度欄位的最大總分葉大小
如果非叢集索引確實包含任何資料行的話,此時除了需要套用先前估算出來的一些結果之外,還要加上一些適當的數值進行調整,其公式如下所列:
Num_Leaf_Cols = Num_Key_Cols + 所包含的資料行數目
Fixed_Leaf_Size =
Fixed_Key_Size + 所包含行固定長度的資料行總大小
Num_Variable_Leaf_Cols =
Num_Variable_Key_Cols + 所包含的變動程度資料行數目
Max_Var_Leaf_Size =
Max_Var_Key_Size + 所包含行變動長度的資料行總大小
2. 接著考慮資料列定位器的大小。
如果非叢集索引不是唯一的,由於資料列定位器的會與非叢集索引會進行組合,以便替每列產生唯一的鍵值。我們在先前已經考慮過這種情況,此時就不需要再作其他的計算,直接進入下一個步驟。
如果非叢集索引是唯一的,則資料列定位器是沒有叢集索引資料表的RID(大小是8個Bytes),此時公式如下:
Num_Leaf_Cols = Num_Leaf_Cols
Num_Variable_Leaf_Cols = Num_Variable_Leaf_Cols
Max_Var_Leaf_Size =Max_Var_Leaf_Size + 8
如果非叢集索引是位於叢集索引上,那麼資料列定位器就是叢集索引鍵欄位。這些欄位必須與非叢集索引鍵結合,而這些欄位是位於叢集索引鍵中的資料欄位,但這些資料欄位並未存在於非叢集索引鍵資料欄位的集合中。這些欄位的空間大小,可依下列公式計算出來:
Num_Leaf_Cols = Num_Leaf_Cols +
不位於非叢集索引鍵資料欄位集合中的叢集索引鍵
資料欄位的數目(如果叢集索引不是唯一的,則 + 1)
Fixed_Leaf_Size = Fixed_Leaf_Size +
不位於非叢集索引鍵資料欄位集合中的固定長度叢集索引
資料欄位的總位元組大小
Num_Variable_Leaf_Cols = Num_Variable_Leaf_Cols +
不位於非叢集索引鍵資料欄位集合中的變動長度叢集索引鍵
資料欄位的數目(如果叢集索引不是唯一的,則 + 1)
Max_Var_Leaf_Size = Max_Var_Leaf_Size +
不位於非叢集索引鍵資料欄位集合中的變動長度叢集索引鍵
資料欄位的最大位元組大小(如果叢集索引不是唯一的,則 + 4)
在本步驟公式右邊的Num_Leaf_Cols、Num_Variable_Leaf_Cols與Max_Var_Leaf_Size就是直接使用上個步驟所計算出來的值代入。
3. 如果索引鍵值內含固定長度的欄位,則於索引記錄中必須預留一個「虛無位元映射」的空間,此空間的大小可依下列公式計算出來:
Leaf_Null_Bitmap = 2 + (( Num_Leaf_Cols + 7 ) / 8)
Leaf_Null_Bitmap:分葉虛無位元映射空間的大小
Num_Leaf_Cols:索引鍵中的分葉數目
如果計算所得的Leaf_Null_Bitmap出現小數,請將小數捨去而只取整數的部分。
4. 如果索引鍵值內含變動長度的欄位,請採用下列公式計算出於索引記錄中需要多少空間來存放這些欄位:
Variable_Leaf_Size =
2 + ( Num_Variable_Leaf_Cols × 2 ) + Max_Var_Leaf_Size
Variable_Leaf_Size:變動長度欄位的總分葉大小
Num_Variable_Leaf_Cols:索引鍵中變動長度欄位的分葉數目
Max_Var_Leaf_Size:所有變動長度欄位的最大總分葉大小
如果索引鍵值中並未包含變動長度的欄位,請將Variable_Leaf_Size設定成0。
本公式係假設所有的變動長度欄位係百分之百被填滿,如果您的變動長度欄位並非百分之百被填滿,請自行於上述公式中,將Max_Var_Leaf_Size乘上填滿因數的百分比,以便更精確估算出索引的大小。
5. 請依下列公式計算出分葉索引列的大小:
Leaf_Row_Size = Fixed_Leaf_Size + Variable_Leaf_Size +
Leaf_Null_Bitmap + 1 + 6
Leaf_Row_Size:分葉索引列的總大小
公式等號右側的數字1為索引列中標頭檔所佔用的大小,而數字6則為子分頁ID指標所佔用的大小。
6. 緊接著,我們可以使用下列公式計算出平均每一個分頁能夠存放多少筆分葉索引列:
Leaf_Rows_Per_Page = ( 8096 ) / ( Leaf_Row_Size + 2 )
Leaf_Rows_Per_Page:平均每一個分頁能夠存放的分葉索引列數目
由於分葉索引列並不會橫跨分頁存放,因此計算出之平均每一個分頁的分葉索引列數目若出現小數,應將其無條件捨去,並取最接近的整數索引列數目。公式中要加上2這個值,乃是分頁位置陣列中該資料列的位置(Entry)。
7. 現在,請依非叢集索引的填滿因數(Fill Factor)來計算出每一個分頁的預留剩餘空間足夠存放多少筆資料列。計算公式如下所示:
Free_Rows_Per_Page =
8096 × (( 100 - Fill_Factor ) / 100 ) / ( Leaf_Row_Size + 2 )
Free_Rows_Per_Page:
平均每一個分頁的剩餘空間足夠存放多少筆資料列
請注意,公式中的 Fill_Factor 是非叢集索引的填滿因數,此值是一個整數值而不是百分比。因為資料列並不會橫跨分頁存放,所以若計算出的 Free_Rows_Per_Page 出現小數,應將其無條件捨去,並取最接近的整數索引列數目。因此當填滿因數增大時,每個分頁所能儲存的資料將更多,而所需佔用的分頁也隨之減少。公式中的數字 2 乃是分頁位置陣列中該資料列的位置(Entry)。
8. 請使用下列公式計算出需要多少分頁去儲存所有資料列:
Num_Leaf_Pages =
Num_Rows / ( Leaf_Rows_Per_Page - Free_Rows_Per_Page)
計算出來的分頁數目必須無條件進位成整數的分頁數目。
9. 終於,我們可以使用下列公式計算出分頁索引的大小:
分頁索引的大小 = 8192 × Num_Leaf_Pages
還記得嗎?每一個分頁的大小是 8,192 個 Bytes 哦!
OK!將在非叢集索引之非分葉層級所計算出來的索引大小,與在非叢集索引的分葉層級中計算所得的索引大小進行加總,這才是整個非叢集索引資料表的大小,其公式如下所列:
非叢集索引的大小(單位:Bytes) = 索引的大小 + 分頁索引的大小
您現在已經如何去估算出一個非叢集索引的大小。當然,假如您的資料表擁有多個非叢集索引,您必須一一去估算出各個非叢集索引的大小,然後再將各個非叢集索引的大小加總起來。
估算一個叢集索引資料表的大小
資料表只能擁有一個叢集索引,而欲估算叢集索引所需的儲存空間,必須先估算在叢集索引之分葉層級(Leaf Level)所能儲存索引的大小,然後再估算在叢集索引中所能儲存索引的大小,再將這兩者的大小加總才是整個叢集索引資料表的大小。
請依下列步驟來估算資料表在叢集索引之分葉層級所能儲存索引的大小:
1. 叢集索引的鍵值可以內含固定長度與變動長度的欄位,您必須計算這些欄位於索引記錄中佔用多少空間。每一個欄位的大小取決其資料型別與長度,相關資訊請參閱圖表 1。
2. 如果叢集索引不是唯一的,就需要將 uniqueifier 資料列計算在內。
uniqueifier 是一個我們看不到且無法存取的變動長度欄位,當叢集索引不是以唯一的時候,SQL Server會自動將 4 個位元組的 uniqueifier 資料行加入資料表,以確保每個索引鍵都是唯一的。
Num_Cols = Num_Cols + 1
Num_Variable_Cols = Num_Variable_Cols + 1
Max_Var_Size = Max_Var_Size + 4
Num_Cols:索引鍵中的欄位數目(包含固定長度與變動長度的欄位)
Num_Variable_Cols:索引鍵中變動長度欄位的數目
Max_Var_Size:所有變動長度鍵值欄的最大總大小
3. 可以保留資料列的一部份,稱為「虛無位元映射」的空間,用來管理資料列的Null屬性,此空間的大小可依下列公式計算出來:
Null_Bitmap = 2 + (( Num_Cols + 7 ) / 8)
Null_Bitmap:索引虛無位元映射空間的大小
Num_Cols:索引鍵資料欄位之個數(包含固定長度與變動長度的欄位)
如果計算所得的 Null_Bitmap 出現小數,請將小數捨去而只取整數的部分。
4. 如果索引鍵值內含變動長度的欄位,請採用下列公式計算出於索引記錄中需要多少空間來存放這些欄位:
Variable_Data_Size =
2 + ( Num_Variable_Cols × 2 ) + Max_Var_Size
Variable_Data_Size:變動長度欄位的總大小
如果索引鍵值中並未包含變動長度的欄位,請將 Variable_Data_Size 設定成 0。
本公式係假設所有的變動長度鍵值欄位係百分之百被填滿,如果您的變動長度鍵值欄位並非百分之百被填滿,請自行於上述公式中,將 Max_Var_Data_Size 乘上填滿因數的百分比,以便更精確估算出索引的大小。
5. 至此,我們可以使用下列公式計算出索引列的大小:
Row_Size =
Fixed_Data_Size + Variable_Data_Size + Null_Bitmap + 4
Row_Size:索引列的總大小
Fixed_Data_Size:所有固定長度欄位的總大小
公式等號右側的數字 4 為索引列中標頭檔所佔用的大小。
6. 緊接著,我們可以使用下列公式計算出平均每一個分頁能夠存放多少筆索引列:
Rows_Per_Page = ( 8096 ) / ( Row_Size + 2 )
Rows_Per_Page:平均每一個分頁能夠存放的索引列數目
由於索引列並不會橫跨分頁存放,因此計算出之平均每一個分頁的索引列數目若出現小數,應將其無條件捨去,並取最接近的整數索引列數目。公式中要加上 2 這個值,乃是分頁位置陣列中該資料列的位置(Entry)。
7. 現在,請依叢集索引的填滿因數(Fill Factor)來計算出每一個分頁的預留剩餘空間足夠存放多少筆資料列。計算公式如下所示:
Free_Rows_Per_Page =
8096 × (( 100 - Fill_Factor ) / 100 ) / ( Row_Size + 2 )
Free_Rows_Per_Page:
平均每一個分頁的剩餘空間足夠存放多少筆資料列
請注意,公式中的 Fill_Factor 是叢集索引的填滿因數,此值是一個整數值而不是百分比。因為資料列並不會橫跨分頁存放,所以若計算出的 Free_Rows_Per_Page 出現小數,應將其無條件捨去,並取最接近的整數索引列數目。因此當填滿因數增大時,每個分頁所能儲存的資料將更多,而所需佔用的分頁也隨之減少。公式中的數字 2 乃是分頁位置陣列中該資料列的位置(Entry)。
8. 請使用下列公式計算出需要多少分頁去儲存所有資料列:
Num_Pages =
Num_Rows / ( Rows_Per_Page - Free_Rows_Per_Page)
計算出來的分頁數目必須無條件進位成整數的分頁數目。
9. 終於,我們可以使用下列公式計算出在分葉層級所能儲存索引的大小:
分葉層級的大小 = 8192 × Num_Pages
等號右邊的數字 8,192 是每個分頁的大小(單位:Bytes)。
OK!您現在已經知道如何去估算資料表在叢集索引之分葉層級所能儲存索引的大小。現在我們要繼續討論要如何估算存放叢集索引資訊所用的大小。請依下列步驟進行:
1. 如果您的索引鍵內含固定長度與變動長度的欄位,必須計算這些欄位佔用多少空間。每一個欄位的大小取決其資料型別與長度,相關資訊請參閱圖表 1。
2. 如果叢集索引不是唯一的話,就需要將 uniqueifier 資料列計算在內。
uniqueifier 是一個我們看不到且無法存取的變動長度欄位,當叢集索引不是以唯一的時候,SQL Server會自動將 4 個位元組的 uniqueifier 資料行加入資料表,以確保每個索引鍵都是唯一的。
Num_Key_Cols = Num_Key_Cols + 1
Num_Variable_Key_Cols = Num_Variable_Key_Cols + 1
Max_Var_Key_Size = Max_Var_Key_Size + 4
Num_Key_Cols:
索引鍵中的欄位數目(包含固定長度與變動長度的欄位)
Num_Variable_Key_Cols:索引鍵中變動長度欄位的數目
Max_Var_Key_Size:所有變動長度鍵值欄的最大總大小
3. 可以保留資料列的一部份,稱為「虛無位元映射」的空間,用來管理資料列的 Null 屬性,此空間的大小可依下列公式計算出來:
Index_Null_Bitmap = 2 + (( Num_Null_Key_Cols + 7 ) / 8)
Index_Null_Bitmap:索引虛無位元映射空間的大小
Num_Null_Key_Cols:可為 Null 的索引鍵資料欄位之個數
如果計算所得的 Index_Null_Bitmap 出現小數,請將小數捨去而只取整數的部分。如果沒有可為Null的索引鍵資料欄位時,也就是當 Num_Null_Key_Cols 個數為 0時,請直接將 Index_Null_Bitmap 設定為 0。
4. 如果索引鍵值內含變動長度的欄位,請採用下列公式計算出於索引記錄中需要多少空間來存放這些欄位:
Variable_Key_Size = 2 + ( Num_Variable_Key_Cols × 2 ) + Max_Var_Key_Size
Variable_Key_Size:變動長度欄位的總大小
Num_Variable_Key_Cols:索引鍵中變動長度欄位的數目
Max_Var_Key_Size:所有變動長度索引鍵欄位的最大總大小
如果索引鍵值中並未包含變動長度的欄位,請將 Variable_Key_Size 設定成 0。
本公式係假設所有的變動長度鍵值欄位係百分之百被填滿,如果您的變動長度鍵值欄位並非百分之百被填滿,請自行於上述公式中,將 Max_Var_Key_Size 乘上填滿因數的百分比,以便更精確估算出索引的大小。
5. 至此,我們可以使用下列公式計算出索引列的大小:
Index_Row_Size = Fixed_Key_Size + Variable_Key_Size +
Index_Null_Bitmap + 1 + 6
Index_Row_Size:索引列的總大小
Fixed_Key_Size:所有固定長度索引鍵欄位的總大小
公式等號右側的數字 1 為索引列中標頭檔所佔用的大小,而數字 6 則為子分頁 ID 指標所佔用的大小。
6. 緊接著,我們可以使用下列公式計算出平均每一個分頁能夠存放多少筆索引列:
Index_Rows_Per_Page = ( 8096 ) / ( Index_Row_Size + 2 )
Index_Rows_Per_Page:平均每一個分頁能夠存放的索引列數目
由於索引列並不會橫跨分頁存放,因此計算出之平均每一個分頁的索引列數目若出現小數,應將其無條件捨去,並取最接近的整數索引列數目。公式中要加上 2 這個值,乃是分頁位置陣列中該資料列的位置(Entry)。
7. 現在要計算出在索引中包含多少層級,計算公式如下所示:
Levels =
1 + log Index_Rows_Per_Page ( Num_Rows / Index_Rows_Per_Page )
Levels:在索引中的層級數
Num_Rows:在資料表中的資料列數目
要注意的是,計算出來的索引層級數並不包含叢集索引的分葉層級。
8. 緊接著,使用下列公式計算出位於索引中的分頁總數:
Num_Index_Pages = Σ Level ( Index_Rows_Per_Page ) Level - 1
Num_Index_Pages:索引中的分頁數目
1 <= Level <= Levels
舉個簡單的例子來說明上面公式的計算方法,假設在分葉層級以上的索引列總數是1,000,平均每個分頁可以存放10個索引列,這也就是說,共需100個分頁來存放這1,000個索引列。在索引的下一個層級要存放100個索引列,需要10個分頁。索引的最後一個層級要存放10個索引列,因此只需要1個分頁。
其套入公式的演算過程如下所示:
Levels = 1 + log 10 ( 1000 / 10 ) = 3
一共需要3層索引
Num_Index_Pages=( 10 ) 3 - 1 + ( 10 ) 2 - 1 + ( 10 ) 1 - 1 =111
因此,在索引中的分頁數目為111。
9. 終於,我們可以使用下列公式計算出索引的大小:
索引的大小 = 8192 × Num_Index_Pages
不要忘記哦!每一個分頁的大小是8,192個Bytes。
OK!將在叢集索引之分葉層級所計算出來的索引大小,與在叢集索引中計算所得的索引大小進行加總,這才是整個叢集索引資料表的大小,其公式如下所列:
叢集索引的大小(單位:Bytes) =分葉層級的大小 + 索引的大小
您現在已經如何去估算出一個叢集索引的大小。當然,假如您的資料表擁有多個叢集索引,您必須一一去估算出各個叢集索引的大小,然後再將各個叢集索引的大小加總起來。
估算一個記錄檔的大小
一 般而言,我們會以資料檔大小的四分之一作為記錄檔的大小,不過這只是一個初估值,畢竟資料的存取頻率及存取對象會大大影響記錄檔的膨脹速度,而這有賴您在 應用系統實際執行時加以監控才能確實估計。此外,由於我們通常會在備份記錄檔之後隨即清理記錄檔,因此備份記錄檔的頻率亦會決定您到底需要一個多大的空間 來存放記錄檔。比方說,如果您的記錄檔每天會膨脹10 MB,而您每五天就會備份一次記錄檔,則只需要
其實以資料檔大小的四分之一作為記錄檔的大小是一個非常不錯的預估方式,不過假如您經常執行下列操作,則必須考慮多配置一些空間給記錄檔:
r 經常新增、修改、與刪除大量資料。
r 異動交易(Transaction)經過很長的期間才執行認可(Commit)。