進行數據庫管理和開發包括數據庫性能分析和優化,須要瞭解數據庫內部的存儲結構。不然,不少數據庫的優化工做沒法展開。SQLServer數據庫存儲的最基本單位是數據頁,系統保存數據和讀取數據都是以頁爲單位來進行操做。數據庫
1、數據頁的基本組成數據庫設計
SQLServer數據庫的一個數據頁基本上包括三部份內容:分別爲標頭、數據行和行偏移量。其中數據行存儲的是數據自己,標頭與偏移量是一些輔助內容。性能
數據頁的大小。在SQLServer數據庫中數據頁的大小基本上是固定的,即每一個數據頁的大小都爲8KB即8192個字節。其中每頁開頭都有一個標頭96個字節,用於存儲有關頁的信息如頁被分配到的頁碼、頁的類型、頁的可用空間以及擁有這個頁的對象的分配單元ID等等信息,這些內容數據庫都會自動管理與更新。數據庫開發者只須要知道這個數據頁中最多能夠用來保存數據的空間大小。每一個頁的大小是8192個字節,扣除掉一些必要的開銷(如標頭信息或者偏移量所佔用的空間),通常其能夠用來實際存儲數據的空間只有8000字節左右。大數據
行的放置順序。在每一個數據頁上,數據行緊接着標頭按順序放置。在頁的末尾有一張行偏移表。對於頁中的每一行,偏移表都包含一條對應條目。即頁的數據有100行則在這個行偏移表中就對應100條偏移量。每一個條目中記錄對應行的第一個字節與頁首的距離。如第二個條目就記錄着第二個數據行的行首字母到數據頁頁首的位置。因爲每一個數據行的大小都是不一樣的,所以偏移量也是不均勻的。行偏移表中的條目順序與頁中行的順序是相反的。這主要是爲了更方便數據庫定位數據行。
2、大數據類型與行優化
根據SQLServer數據庫定義的規則,行是不可以跨頁的。若是一個字段長度很是大超過了8000字節,此時一個頁已經不可以容納這個數據。此時數據庫會如何處理呢?在SQLServer數據庫中,行不能跨頁,因而將行分紅兩部分分別存儲在不一樣的行中。因此說,對於大數據類型來講,是不受到這個頁大小(或者說行大小)的限制的。根據上面的分析能夠看出,一個數據頁其最大能夠用的存儲空間在8KB。若是扣掉一些必要的開銷,其只有8000字節左右。若是某條記錄的全部列(包括固定長度的列與可變長度的列其大小超過這個限制,數據庫就會將其進行分行處理,分別存儲在兩個不一樣的頁中。某表中列的總大小超過限制的8KB,數據庫系統會從最大長度的列開始動態的將一個或多個可變長度列移動到另一個頁中。簡單的說,就是將某個列超過的部分單獨存放在另外一個頁中。而且同時還會存儲一些指針之類的信息,以便在不一樣頁的記錄中創建關聯。這種現象在SQLServer數據庫中給其取了一個名字,叫作行溢出。設計
3、行溢出對於數據庫性能的不利影響。指針
當全部列(包括固定長度的列與可變長度的列)的累積長度超過一個數據頁(或者一個數據行)的最大承受限度時,會將列的內容分行來進行存放。通常來講,每行的記錄超過頁的最大容量時,確定會對數據庫的性能形成不利的影響。這是毋庸置疑的。由於當超過這個容量時,數據庫系統就須要對這個數據行進行分頁處理。而分頁處理須要數據庫額外的開銷。如在分頁保存時,須要給數據庫添加額外的指針;在查詢數據的時候,因爲分頁狀況的存在,爲了讀取一條完整的記錄,數據庫系統可能不得不讀取多頁的內容;當進行更新操做,將某個字段的內容變短,致使整行的內容在頁的最大範圍以內,則相關的記錄會被保存在同一個行中。這些操做都須要數據庫額外的開銷。當在同一個時間處理這些做業多了,那麼積累起來,對數據庫性能的影響就會很顯著。同理,此時若是對相關的記錄進行排序、統計等操做,因爲涉及到多個頁,會延長這些做業的執行時間,即下降數據庫的性能。在SQLServre數據庫中,含有varchar等變長的數據類型。在SQLServer數據庫中對此有最大長度的限制。通常狀況下,其最大長度不可以超過不可以超過8000字節的限制。不過他們的總寬度能夠超過這個8KB的限制。若是單列的數據長度超過這個限制,那麼就不可以使用普通的數據類型。如對於那些用來保存圖片或者多媒體的數據,必需要使用大對象數據類型。由於只有這些大對象數據類型不受這個長度的限制。數據庫對對於這些大型數據庫類型對象有特殊的處理方法。code
4、數據庫設計時的注意事項。對象
在數據庫運行時,若是存在比較多的行溢出現象,會在很大程度上影響數據庫的性能。因此在數據庫設計時,須要考慮到這種狀況。通常的數據類型不會形成行溢出的狀況。只有一些varchar nvarchar或者CLR用戶自定義類型的列,比較容易形成這個行溢出現象。因此在設計數據庫時,數據庫管理員應該根據用戶提供的樣板數據分析可能發生行溢出現象的百分比,以及評估會發生溢出現象的頻率。若是溢出現象發生的百分比或者頻率比較高的話,那麼數據庫管理員就須要考慮對錶格進行規範化處理,以提升數據庫的性能,減小溢出現象對於數據庫的不利影響。排序
通常來講,有兩種方法能夠顯著的下降這個行溢出現象對數據庫性能的影響。一是假設列定義了varchar或者用戶自定義數據類型等數據類型的時候,若是其長度比較長,頗有可能引發行溢出現象的話,那麼就乾脆使用大對象數據類型。對於大對象數據類型SQLServer數據庫會採起特殊的管理方法,會講這個數據與普通數據分開來管理。因此能夠在很大程度上下降行溢出現象對數據庫性能的影響。不過須要注意的是,管理這些大對象數據類型,數據庫自己就須要花費更多的精力與資源。因此採用這種方式帶來的收益,與行溢出現象帶來的損失就會有一個輕重之分的問題。數據庫管理員要評估由此帶來的收益可以彌補行溢出對象帶來的損失。若是能夠彌補的話,那麼能夠採用這個方案。若是不能夠的話,那就得不償失了。故筆者並非很推薦使用這種方法。
第二種方法執行起來比較簡單,具備比較強的可執行性。即若是某個表格中有varchar或則用戶自定義的數據類型,並且其最大長度也比較長,很容易形成行溢出現象。此時最好將這些列與表中的其餘列分開來存放。即將他們放在兩張不一樣的表中。而後再經過join語句來進行鏈接。因爲數據頁對單個列的最大長度有限制,因此如此處理的話,就不怎麼會發生行溢出的現象。此時若是須要查詢完整的記錄,也須要訪問多個頁。可是在實際工做中,每每不須要訪問所有的信息。如在更新或者統計操做時,不須要更新varchar數據類型的字段,那麼數據庫的效率就會有很大的提高。即便須要訪問完整的記錄,須要訪問多個頁。可是採起join操做也要比行溢出操做性能來的好。如在更新數據時將varchar的列縮短了,此時因爲在兩個不一樣的表中,也不會出現合併行的問題。因此能夠在很大程度上節省數據庫的開銷。顯然,這種分表處理的方式更加簡單,很容易操做,能夠採用這種方式來避免行溢出對SQLServer數據庫形成的不利影響。