深入淺出分區表與分區索引之二:分區的發展歷史

分區的概念對 SQL Server 來說並不陌生。實際上,此產品的每個版本中都可以實現不同形式的分區。但是,由於沒有爲了幫助用戶創建和維護分區架構而專門設計一些功能,因此分區一直是一個很繁瑣的過程,沒有得到充分的利用。而且,用戶和開發人員對此架構存在誤解(由於其數據庫設計比較複雜),低估了它的優點。但是,由於概念中固有的重要性能改善,SQL Server 7.0 開始通過分區視圖實現各種分區方式,以此來改進這種功能。現在,SQL Server 2005 爲通過分區表對大型數據集進行分區又邁出了最大的一步。 

對 SQL Server 7.0 之前的版本中的對象進行分區 

在 SQL Server 6.5 及以前的版本中,分區只能通過設計來完成,還必須內置到所有數據訪問編碼和查詢方法中。通過創建多個表,然後通過存儲過程、視圖或客戶端應用程序管理對正確表的訪問,通常可以改善某些操作的性能,但代價是增加了設計的複雜性。每個用戶和開發人員都必須知道(並正確引用)正確的表。

單獨創建和管理每個分區,而使用視圖來簡化訪問;但是這種解決方案對性能並沒有太大的改善。使用聯合視圖簡化用戶和應用程序訪問時,查詢處理器必須訪問每個基礎表才能確定結果集所需的數據。如果只需要基礎表的有限子集,則每個用戶和開發人員都必須瞭解此設計,以便只引用相應的表。 

SQL Server 7.0 中的分區視圖 

在 SQL Server 7.0 之前的版本中,手動創建分區所面臨的挑戰主要與性能有關。儘管視圖可以簡化應用程序設計、用戶訪問和查詢的編寫,但卻無法改善性能。而在 SQL Server 7.0 版本中,視圖結合了約束,允許查詢優化程序從查詢計劃中刪除不相關的表(即分區消除),大大降低了聯合視圖訪問多個表時的總計劃成本。 

請參見圖  中的 YearlySales 視圖。您可以定義十二個單獨的表(如 SalesJanuary2003SalesFebruary2003 等),然後定義每個季度的視圖以及全年的視圖 YearlySales,而不是將所有銷售數據放到一個大型表中。 



使用以下查詢訪問 YearlySales 視圖的用戶只會被引導至 SalesJanuary2003 表。
SELECT ys.* 
FROM dbo.YearlySales AS ys
WHERE ys.SalesDate = '20030113'


只要約束可信並且訪問視圖的查詢使用 WHERE 子句根據分區鍵(定義約束的列)限制查詢結果,SQL Server 就會只訪問必需的基礎表。受信任的約束是指 SQL Server 能夠確保所有數據符合該約束所定義的屬性的約束。創建約束時,默認行爲是創建約束 WITH CHECK。此設置將導致對錶執行架構鎖定,以便根據約束驗證數據。如果驗證結果表明現有數據有效,則添加約束;一旦解除架構鎖定,後續的插入、更新和刪除操作都必須符合正在應用的約束。

通過使用此過程創建受信任的約束,開發人員無需直接訪問(甚至不需要知道)他們感興趣的表,從而大大降低了使用視圖的設計的複雜性。通過受信任的約束,SQL Server 可以從執行計劃中刪除不需要的表,從而改善性能。 

注意:約束可以通過各種方式變得“不可信任”;例如,如果未指定 CHECK_CONSTRAINTS 參數即執行批量插入,或者使用 NOCHECK 創建約束。如果約束不可信任,查詢處理器將轉而掃描所有基礎表,因爲它無法確定所請求的數據是否真的位於正確的基礎表中。

SQL Server 2000 中的分區視圖 

儘管 SQL Server 7.0 大大簡化了設計並改善了 SELECT 語句的性能,但是並沒有爲數據修改語句帶來任何好處。INSERT、UPDATE 和 DELETE 語句只能針對基礎表,而不能直接針對用於聯合表的視圖。在 SQL Server 2000 中,數據修改語句還可以受益於 SQL Server 7.0 中引入的分區視圖功能。由於數據修改語句可以使用相同的分區視圖結構,因此,SQL Server 可以通過視圖將修改定向至相應的基礎表。爲了正確配置此設置,需要對分區鍵及其創建設置額外的限制;但是,基本原理是相同的,因爲 SELECT 查詢與修改都會直接發送給相應的基礎表。

SQL Server 2005 中的分區表 

儘管 SQL Server 7.0 和 SQL Server 2000 中的改進大大改善了使用分區視圖時的性能,但是並沒有簡化分區數據集的管理、設計或開發。使用分區視圖時,必須單獨創建和管理每個基礎表(在其中定義視圖的表)。儘管簡化了應用程序設計併爲用戶帶來了好處(用戶不再需要知道直接訪問哪個基礎表),但是由於要管理的表太多,而且必須爲每個表管理數據完整性約束,管理工作變得更復雜。因爲管理方面的問題,通常只有在需要存檔或加載數據時才使用分區視圖來分離表。當數據被移動到只讀表或從只讀表中刪除後,操作的代價變得十分高昂,不僅花費時間、佔據日誌空間,通常還會導致系統阻塞。 

另外,由於以前版本中的分區策略需要開發人員創建各個表和索引,然後通過視圖將它們聯合起來,因此優化程序需要驗證並確定每個分區的計劃(因爲索引可能已發生變化)。這樣一來,SQL Server 2000 中的查詢優化時間通常會隨着處理的分區數增加而直線上升。 

在 SQL Server 2005 中,從定義上講,每個分區都擁有相同的索引。例如,請考慮這樣一種方案,即當前月份的聯機事務處理 (OLTP) 數據需要移動到每個月末的分析表中。分析表(用於只讀查詢)是具有一個羣集索引和兩個非羣集索引的表;批量加載 1 GB 數據(加載到已建立索引並激活的一個表中)將使當前用戶遭受系統阻塞的情況,因爲表和/或索引變得支離破碎和/或被鎖定。另外,因爲每傳入一行都需要維護表和索引,所以加載過程還將耗費大量的時間。雖然可以通過多種方法加快批量加載的速度,但這些方法可能會直接影響所有其他用戶,因爲追求速度而無法實現併發操作。 

如果將這些數據單獨放到一個新創建的(空)且未建立索引(堆)的表中,則可以先加載數據,而在加載數據之後建立索引。通常情況下,使用這種架構可以獲得十倍或更好的性能。實際上,通過加載未建立索引的表可以利用多個 CPU,因爲可以並行加載多個數據文件或從同一個文件中加載多個數據塊(通過開始和結束行位置來定義)。由於兩個操作都可以通過並行獲益,因此可以更進一步改善性能。 

在 SQL Server 的任何版本中,分區都使您可以獲得更精確的控制,而且不需要將所有數據放到一個位置;但是,需要創建和管理許多對象。在以前的版本中,通過動態創建表、刪除表以及修改聯合視圖,可以實現功能性分區策略。但是,SQL Server 2005 中的解決方案更加完善:您可以輕鬆地移入新填充的分區(作爲現有分區架構的額外分區),還可以移出任何舊分區。整個過程只需要很短的時間即可完成,通過使用並行批量加載和並行索引建立,還可以進一步提高效率。更重要的是,因爲分區是在表範圍之外進行管理的,所以添加分區之前不會對所查詢的表造成任何影響。結果是,添加一個分區通常只需要幾秒鐘。 

需要刪除數據時的性能改善也很顯著。如果一個數據庫需要一個滑動窗口數據集,用於移植新數據(例如當前月份的數據)並刪除最早的數據(可能是上一年同一月份的數據),那麼使用分區可以將數據移植的性能提高几個數量級。雖然這看起來好像很大,但考慮了未分區的區別;當所有數據位於一個表中時,刪除 1 GB 的舊數據需要對錶及其相關索引進行逐行處理。刪除數據的過程將創建大量的日誌活動,不允許在刪除的過程中出現日誌截斷問題(注意,刪除是一個自動提交的事務;但是,可以通過儘可能地執行多個刪除操作來控制事務的大小),因此,可能需要更大的日誌。但是,如果使用分區,刪除相同數量的數據需要從分區表中刪除特定的分區(一種元數據操作),然後刪除或截斷獨立的表。

此外,如果不知道如何才能最好地設計分區,則不可能認識到將文件組與分區結合使用是實現分區的理想選擇。文件組允許您將各個表放置到不同的物理磁盤上。如果一個表包含多個文件(使用文件組),則無法預測數據的物理位置。對於不需要使用並行操作的系統來說,SQL Server 可以在文件組之間更平均地使用所有磁盤,使數據具體放在什麼位置變得不是那麼重要,從而提高系統的性能。 

注意:在下圖 中,一個文件組包含三個文件。


此文件組中放置了兩個表,即 Orders 和 OrderDetails。將表放置到文件組中時,SQL Server 將根據文件組中的對象需要的空間,從每個文件中獲得盤區分配(64-KB 塊,相當於八個 8-KB 頁面),按比例填充文件組中的文件。創建 Orders 和 OrderDetails 表時,文件組是空的。創建訂單時,數據被輸入到Orders 表中(每個訂單佔據一行),並且按照每個明細項一行的方式輸入到 OrderDetails 表中。

SQL Server 將一個盤區分配給文件 1 中的 Orders 表,將另一個盤區分配給文件 2 中的 OrderDetails 表。OrderDetails 表的增長速度可能比 Orders 錶快,後續的分配將轉到下一個需要空間的表中。隨着 OrderDetails 表的增長,它將從文件 3 中獲取下一個盤區,而 SQL Server 將繼續在文件組的文件之間“循環”下去。在圖 中,就是從每個表到盤區,再從每個盤區到相應的文件組。盤區是按照需要的空間進行分配的,而根據流程進行編號。 


SQL Server 繼續在文件組中的所有對象之間平衡分配。如果增加給定操作使用的磁盤數,雖然 SQL Server 可以更有效地運行,但從管理或維護的角度來說,增加磁盤數並非最佳選擇,尤其是在使用模式幾乎可以預測(且已隔離)的情況下。因爲數據在磁盤上的位置並不明確,所以您無法隔離數據以執行備份等維護操作。

通過 SQL Server 2005 中的分區表,可以對錶進行設計(使用函數和架構),從而將具有相同分區鍵的所有行都直接放置到(且總是轉到)特定的位置。函數用於定義分區邊界以及放置第一個值的分區。在使用 LEFT 分區函數時,第一個值將作爲第一個分區中的上邊界。在使用 RIGHT 分區函數時,第一個值將作爲第二個分區的下邊界(本文後面將更詳細地介紹分區函數)。

定義函數後即可創建分區架構,以定義分區到其數據庫位置的物理映射(根據分區函數)。當多個表使用同一個函數(但不一定使用同一個架構)時,將按類似的方式對具有相同分區鍵的行進行分組。此概念稱爲對齊。通過將來自多個表但具有相同分區鍵的行對齊到相同或不同的物理磁盤上,SQL Server 可以(如果優化程序做出此選擇)只處理每個表中必要的數據組。要實現對齊,兩個分區表或索引所在的相應分區之間必須具有某種對應性。它們必須爲分區列使用等效的分區函數。如果滿足以下條件,兩個分區函數則可以用來對齊數據: 


  • 兩個分區函數使用相同數量的參數和分區。 

  • 每個函數中使用的分區鍵具有相同的類型(包括長度和精度,如果適用,還包括縮放和排序)。 

  • 邊界值相等(包括 LEFT/RIGHT 邊界標準)。 


注意即使兩個分區函數都用於對齊數據,但如果沒有在與分區表相同的列上分區,最後的索引也可能無法對齊。

排序是一種更強大的對齊方式,通過排序,兩個對齊的對象將用一個 equi-join 謂詞連接起來(equi-join 位於分區列上)。在可能出現 equi-join 謂詞的查詢、子查詢或其他類似結構的上下文中,這變得很重要。排序之所以重要,因爲在分區列上連接表的查詢一般都非常快。以上圖 中的 Orders 和OrderDetails 表爲例,除了按比例填充文件之外,還可以創建映射到三個文件組的分區架構。

定義 Orders 和 OrderDetails 表時,將它們定義爲使用相同的架構。具有相同分區鍵值的相關數據將被放置到同一個文件中,而將必要的數據隔離出來以便進行連接。如果來自多個表的相關行都按照相同的方式進行分區,SQL Server 則可以連接分區,而無需在整個表或多個分區中(如果表使用了不同的分區函數)搜索匹配的行。在這種情況下,不僅可以對齊對象(因爲它們使用相同的鍵),還可以按存儲位置對齊(因爲相同的數據位於相同的文件中)。 

下圖 顯示兩個對象可以使用相同的分區架構,而具有相同分區鍵的所有數據行最後將位於同一個文件組中。對齊相關數據後,SQL Server 2005 可以有效地並行處理大型數據集。例如,1 月份的所有銷售數據(包括 Orders 和 OrderDetails 表中的數據)都位於第一個文件組中,2 月份的數據位於第二個文件組中,依此類推。


SQL Server 允許根據範圍進行分區,還允許將表和索引都設計爲使用相同的架構,以便更好地對齊。好的設計可以大大提高整體性能,但是,如果數據的使用隨着時間而發生變化,該怎麼辦?如果需要額外的分區,又該怎麼辦?簡化從分區表外部添加分區、刪除分區和管理分區等方面的管理工作是 SQL Server 2005 的主要設計目標。 

SQL Server 2005 已經考慮瞭如何簡化分區的管理、開發和使用。它在性能和可管理性方面有以下優點: 

  • 簡化了需要進行分區以改善性能或可管理性的大型表的設計和實現。 
  • 將數據加載到現有分區表的新分區中時,最大程度地減少了對其他分區中的數據訪問的影響。 
  • 將數據加載到現有分區表的新分區中時,性能相當於將同樣的數據加載到新的空表中。 
  • 在存檔和/或刪除分區表的一個分區時,最大程度地減少了對錶中其他分區的訪問的影響。 
  • 允許通過將分區移入和移出分區表來維護分區。 
  • 提供了更好的伸縮性和並行性,可以對多個相關表執行大量操作。 
  • 改善了所有分區的性能。 
  • 縮短了查詢優化時間,因爲不需要單獨優化每個分區。 
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章