歡迎來到SQL Server性能調優培訓的第2個月。這個月將會是最有趣和最有挑戰性的一個月,這個月我們專一只談SQL Server中的索引,索引,還是索引。相信我,值得一個月去學習索引。
今天我會談下堆表(Heap Tables),在接下來的3周,我們會探討下聚集索引,非聚集索引,還有SQL Server的索引戰略。先來看下堆表。堆表就是沒有聚集索引的表。如果SQL Server中的表能有一個聚集索引,那這個表被稱為聚集表(Clustered Table),沒有聚集索引的表,我們稱它為堆表。
在堆表里,數據沒有任何方式的排序,它就是一個無序堆,無結構關聯的記錄。當你使用SELECT語句訪問堆表時,SQL Server在執行計劃里會使用表掃描(Table Scan)運算符,因為你沒有定義合適的聚集索引。(堆表)沒有表查找(Table Seek)這個運算符。這點非常重要。
下周你會學到,當我們提到聚集索引時,你是通過聚集索引掃描(Clustered Index Scan)、聚集索引查找(Clustered Index Seek)運算符來訪問聚集索引的。在堆表你只有一個表掃描(Table Scan)運算符。表掃描意味著你必須掃描整張表,不以你表擁有的數據量來衡量。你的數據量越多,操作花費(時間)越長。
表掃描始終是個線性O(n)操作(更多關于大O介紹),它不以你越來越大的表來衡量。現在讓我們一起詳細看下在SQL Server中堆表的優點和缺點。
優點堆表插入數據非常,非常,非???。如我們剛才說的堆表就是一個數據堆。當你從傳統電話本(拆開裝訂)把每頁扯出來并把各頁放在你面前的桌上時,你就擁有了一個堆表。在堆表的電話本里插入一個新的電話記錄非??欤耗惴峙湟粋€8kb 的新頁,在那頁寫上新的紀錄,最后把那頁與面前的其他頁放一起,搞定。不需要保證任何的排序。
在SQL Server里是一樣的:分配一個新頁,在新頁存新的紀錄,把這頁分配給堆表,搞定。這是一個非常快的方法,因為SQL Server不需要保證任何的排序。把新紀錄存放在哪里完全由SQL Server自己決定。
因此在數據庫架構里,這樣的表設計有些時候是非常好的主意:這些表只有海量(huge) ,并行(parallel)的INSERT活動。考慮下你的登陸/審計表。當我絕不推薦在任何地方使用堆表。這里只是一些特定有意義的使用案例。但不是任何地方。
缺點堆表除了插入數據非常快的優點外,也有很多缺點,當你決定創建堆表時若不考慮這些就不合適了。
第一個缺點,堆表在你訪問表數據時會在存儲子系統引發隨機存?。╮andom I/O) 。想象下對你的堆表執行簡單的SELECT語句。如果數據沒有緩沖在緩沖池,SQL Server會發起從你的存儲系統進行物理讀操作。這些讀操作會是隨機存?。╮andom I/O),因為堆表的頁是存在數據文件里某些地方的,它們并不相鄰。
如果你使用傳統的旋轉存儲(現在大多數情況還是這樣的機械硬盤),在你的存儲級別就有性能上的問題,因為隨機存取是非常,非常慢的。SSD硬盤在這方面是大的游戲規則改變者,因為如果你在SSD硬盤執行隨機存?。╮andom I/O) 或循序存取(sQQuential I/O) ,這些都不是問題。因為兩種操作不管哪樣速度基本都是一樣(隨機存?。╮andom I/O) 比循序存?。╯qquential I/O)稍微慢一點)。
另外一個是明確只有在堆表里才有的被稱為轉發記錄(Forwarding Records) 的問題。存在堆表里的記錄在某些情況下(更新變長記錄會移動記錄的存儲)可以從一頁移動到另一頁。如果這個發生的話,SQL Server會在原頁存放一條指向記錄存放新位置的轉發記錄(Forwarding Record) 。
當你訪問你的數據的時候,SQL Server還是訪問原頁,并通過轉發記錄拿到在額外頁你需要的記錄。這會讓你的讀性能大幅度下降。如果你想了解更多轉發記錄(Forwarding Record)細節,并且如何避免它們,我建議你看下我的關于那個話題的第10個SQL Server Quickie。
小結堆表在一些情況有它們的用處。一般我都建議創建聚集表(在上面定義一個聚集索引),但想下在一些特殊案例下,堆表可能是一個服務你業務需要更好方式(利用它的性能特性)。如果你想了解更多關于什么時候使用堆表更合適的細節,我也推薦Tomas Kejser's的博客帖子 聚集索引與堆表的對抗。Tomas會給你非常有爭議卻仍有用的洞察,(那就是)對你來說關于什么時候使用堆表是有意義的。
下周我會探討更多關于SQL Server中的聚集索引。你會學到如何選擇你的正確聚集主鍵,什么時候它們是好的,還有什么時候是壞的。請繼續關注,下周見。
新聞熱點
疑難解答