SQL Server2005 表分區操作詳解

你是否在千方百計優化SQL Server 數據庫的性能?如果你的數據庫中含有大量的表格,把這些表格分區放入獨立的文件組可能會讓你受益匪淺。SQL Server 2005引入的表分區技術,讓用戶能夠把數據分散存放到不同的物理磁盤中,提高這些磁盤的並行處理性能以優化查詢性能。

  SQL Server數據庫表分區操作過程由三個步驟組成:

  1. 創建分區函數

  2. 創建分區架構

  3. 對錶進行分區

  下面將對每個步驟進行詳細介紹。

  步驟一:創建一個分區函數

  此分區函數用於定義你希望SQL Server如何對數據進行分區的參數值(how)。這個操作並不涉及任何表格,只是單純的定義了一項技術來分割數據。

  我們可以通過指定每個分區的邊界條件來定義分區。例如,假定我們有一份Customers表,其中包含了關於所有客戶的信息,以一一對應的客戶編號(從1到1,000,000)來區分。我們將通過以下的分區函數把這個表分爲四個大小相同的分區:  

CREATE PARTITION FUNCTION customer_partfunc (int)
  AS RANGE RIGHT
  FOR VALUES (250000, 500000, 750000)

  這些邊界值定義了四個分區。第一個分區包括所有值小於250,000的數據,第二個分區包括值在250,000到49,999之間的數據。第三個分區包括值在500,000到7499,999之間的數據。所有值大於或等於750,000的數據被歸入第四個分區。

  請注意,這裏調用的"RANGE RIGHT"語句表明每個分區邊界值是右界。類似的,如果使用"RANGE LEFT"語句,則上述第一個分區應該包括所有值小於或等於250,000的數據,第二個分區的數據值在250,001到500,000之間,以此類推。

  步驟二:創建一個分區架構

  一旦給出描述如何分割數據的分區函數,接着就要創建一個分區架構,用來定義分區位置(where)。創建過程非常直截了當,只要將分區連接到指定的文件組就行了。例如,如果有四個文件組,組名從"fg1"到"fg4",那麼以下的分區架構就能達到想要的效果:  

CREATE PARTITION SCHEME customer_partscheme
  AS PARTITION customer_partfunc
  TO (fg1, fg2, fg3, fg4)

  注意,這裏將一個分區函數連接到了該分區架構,但並沒有將分區架構連接到任何數據表。這就是可複用性起作用的地方了。無論有多少數據庫表,我們都可以使用該分區架構(或僅僅是分區函數)。

  步驟三:對一個表進行分區

  定義好一個分區架構後,就可以着手創建一個分區表了。這是整個分區操作過程中最簡單的一個步驟。只需要在表創建指令中添加一個"ON"語句,用來指定分區架構以及應用該架構的表列。因爲分區架構已經識別了分區函數,所以不需要再指定分區函數了。

  例如,使用以上的分區架構創建一個客戶表,可以調用以下的Transact-SQL指令:  

CREATE TABLE customers (FirstName nvarchar(40), LastName nvarchar(40), CustomerNumber int)
  ON customer_partscheme (CustomerNumber)

  關於SQL Server的表分區功能,你知道上述的相關知識就足夠了。記住!編寫能夠用於多個表的一般的分區函數和分區架構就能夠大大提高可複用性。

------------------------------------------------------------------------------------------------------------

數據庫性能調優是每一個優秀SQL Server管理員最終的責任。雖然保證數據的安全和可用性是我們的最高的目標,但是假如數據庫應用程序無法滿足用戶的要求,那麼DBA們會因爲性能低下的設計和實現而受到指責。SQL Server 2005在數據庫性能方面得到了很多提高,尤其是表分區的技術。如果你還沒不瞭解表分區的特徵,那麼請你花點時間讀這篇文章。

  表分區的概念不是一個新的概念;只要你當過一段時間的SQL Server DBA,那麼你可能已經對一些頻繁訪問的表進行過歸檔,當這個表中的歷史數據變的不再經常被訪問的時候。比如,假設你有一個打印時間報表的應用,你的報告很少會查詢1995年的數據,因爲絕大部分的預算規劃會基於最近幾年的數據。

  在SQL Server的早期版本中,你可以創建多個表。每一個表都具有相同的列結構,用來保存不同年份的數據。這樣,當存在着對歷史數據訪問的必要的時候,你可以創建一個視圖來對這些表進行查詢處理。將數據保存在多個表中是很方便的,因爲相對於查詢時掃描整個大表,掃描小表會更快。但是這種好處只有在你預先知道哪些時間段的數據會被訪問。同時,一旦數據過期,你還需要創建新表並且轉移新產生的歷史數據。

  SQL Server 7和SQL Server 2000支持分佈式分區視圖(distributed partitioned views,又稱爲物化視圖,materialized views).分佈式分區視圖由分佈於多臺服務器上的、具有相同表結構的表構成,而且你還需要爲每一個服務器增加鏈接服務器定義(linked server definitions),最後在其中一臺服務器上創建一個視圖將每臺服務器上返回的數據合併起來。這裏的設計思想是數據庫引擎可以利用多臺服務器的處理能力來滿足查詢。

  但是,分佈式分區視圖(DPV)受到很多限制,你可以在SQL Server的在線幫助文檔中閱讀到。雖然DPV在一些情況下能夠提供性能上的提高,但是這種技術不能被廣泛的應用。已經被證明它們不能滿足逐步增長的企業級應用的要求。何況,DPV的實現是一個費力的過程,需要DBA進行很多工作。

  SQL Server 2005開始支持表分區,這種技術允許所有的表分區都保存在同一臺服務器上。每一個表分區都和在某個文件組(filegroup)中的單個文件關聯。同樣的一個文件/文件組可以容納多個分區表。

  在這種設計架構下,數據庫引擎能夠判定查詢過程中應該訪問哪個分區,而不用掃描整個表。如果查詢需要的數據行分散在多個分區中,SQL Server使用多個處理器對多個分區進行並行查詢。你可以爲在創建表的時候就定義分區的索引。 對小索引的搜索或者掃描要比掃描整個表或者一張大表上的索引要快很多。因此,當對大表進行查詢,表分區可以產生相當大的性能提升。

  現在讓我們通過一個簡單的例子來了解表分區是如何發揮作用的。在這篇文章中,我不想深入到分區的語法細節當中,這些你可以在SQL Server的在線幫助文檔中找到。下面的例子基於存儲着一個時間報表系統的數據的數據倉庫。除了默認的文件組,我另外創建了7個文件組,每一個文件組僅包含一個文件,這個文件將存儲由分區函數定義的一部分數據。

  爲了測試表分區的性能提升,我向這個分區表中插入了一千五百萬行,同時向另外一個具有相同表結構、但是沒有進行分區的表插入了同樣的數據。對分區表執行的INSERT語句運行的更快一些。甚至在我的內存不到1G的筆記本電腦上,對分區表的INSERT語句比不分區的表的INSERT語句要快上三倍。當然,查詢的執行時間依據硬件資源的差異而所有變化,但是你還是能夠在你的環境中感到不同程度的提升。

  我將檢查更深入了一步,通過分別檢查同一條返回所有行的、簡單SELECT語句在分區表和非分區表上的執行計劃,返回的數據範圍通過WHERE語句來指定。同一條語句在這兩個不同的表上有不同的執行計劃。對於分區表的查詢顯示出一個嵌套的循環和索引的掃描。從本質上來說,SQL Server將兩個分區視爲獨立的表,因此使用一個嵌套循環將它們連接起來。對非分區的表的同一個查詢則使用索引掃描來返回同樣的列。當你使用同樣的分區策略創建多個表,同時在查詢中連接這些表,那麼性能上的提升會更加明顯

你可以使用下面的查詢來了解每一個分區中的行的個數:

  SELECT $PARTITION.TimeEntryDateRangePFN(time_entry_date) AS Partition,
  COUNT(*) AS [COUNT] FROM fact_time_entry
  GROUP BY $PARTITION.TimeEntryDateRangePFN(time_entry_date)
  ORDER BY Partition

  表分區對交易環境和數據倉庫環境來說,都是一個重要的特徵。數據倉庫用戶最主要的抱怨是移動事實表(fact table)會花費太多時間。當裝載數據到事實表的時候,用戶查詢(立方體處理查詢)的性能會明顯下降,甚至是完全無法成功。因此,裝載大量的數據到事實表的時候常常需要停機。如果使用表分區,就不再出現這樣的情況——確切的講,你一眨眼的工夫就可以移動事實表。爲了演示這是如何生效的,我使用上面例子中相同的分區函數和表結構來創建一個新的表,這個表叫做fact_time_entry2。表的主鍵從五千萬開始,這樣fact_time_entry2就不會包含表fact_time_entry中已經有的數據。

  現在我把2007年的數據移動到這張fact_time_entry2中。同時讓我們假設fact_time_entry表中包含着2007年之前的數據。在fact_time_entry2表完成數據的轉移,我執行下面的語句:

  ALTER TABLE fact_time_entry2
  SWITCH PARTITION 8 TO fact_time_entry PARTITION 8

  這條語句將編號爲8的分區,這個分區恰好包含着2007年的數據,從fact_time_entry2移動到了fact_time_entry表中,在我的筆記本電腦上,這個過程只花費了3毫秒。在這短短的3毫秒中,我的事實表就增加了五百萬條記錄!的確,我需要在交換分區之前,將數據移動到中間表,但是我的用戶不需要擔心——事實表隨時都可以查詢!在這幕後,實際上沒有數據移動——只是兩張表的元數據發生了變化。

  我可以使用類似的查詢刪除事實表中不在需要的數據。例如,假設我們決定我們不再關心2004年的記錄。下面的語句可以將這些記錄轉移到我們創建的工作表中:

  ALTER TABLE fact_time_entry
  SWITCH PARTITION 2 TO fact_time_entry2 PARTITION 2

  這樣的語句依舊在毫秒級內完成了。現在,我可以刪除fact_time_entry2或者將它移到其他的服務器上。我的事實表不會包含2004年的任何記錄。這個分區還是需要在目的表中存在,而且它必須是空的。你不能將分區轉移到一個包含重複數據的表中。源表和目的表的分區必須一致,同時被轉移的數據必須在同一個文件組中。即使受到這麼多的限制,轉換分區和無需停機就可以移動數據表的功能必將讓數據倉庫的實現變的前所未有的輕鬆。 

---------------------------------------------------------------------------------------------------------------

SQL Server 表分區(partitioned table/Data Partitioning)
  Partitioned Table
  可伸縮性性是數據庫管理系統的一個很重要的方面,在SQL Server 2005中可伸縮性方面提供了表分區功能。
  其實對於有關係弄數據庫產品來說,對錶、數據庫和服務器進行數據分區的從而提供大數據量的支持並不是什麼新鮮事,但 SQL Server 2005 提供了一個新的體系結構功能,用於對數據庫中的文件組進行表分區。水平分區可根據分區架構,將一個表劃分爲幾個較小的分組。表分區功能是針對超大型數據庫(從數百吉字節到數千吉字節或更大)而設計的。超大型數據庫 (VLDB) 查詢性能通過分區得到了改善。通過對廣大分區列值進行分區,可以對數據的子集進行管理,並將其快速、高效地重新分配給其他表。
  設想一個大致的電子交易網站,有一個表存儲了此網站的歷史交易數據,這此數據量可能有上億條,在以前的SQL Server版本中存儲在一個表中不管對於查詢性能還是維護都是件麻煩事,下面我們來看一下在SQL Server2005怎麼提高性能和可管理性:
  -- 創建要使用的測試數據庫,Demo
  USE [master]
  IF EXISTS (SELECT name FROM master.dbo.sysdatabases WHERE name = N'DEMO')
  DROP DATABASE [DEMO]
  CREATE DATABASE [DEMO]
  --由於表分區使用使用新的體系結構,使用文件組來進行表分區,所以我們創建將要用到的6個文件組,來存儲6個時間段的交易數據[<2000],[ 2001], [2002], [2003], [2004], [>2005]
  ALTER DATABASE Demo ADD FILEGROUP YEARFG1;
  ALTER DATABASE Demo ADD FILEGROUP YEARFG2;
  ALTER DATABASE Demo ADD FILEGROUP YEARFG3;
  ALTER DATABASE Demo ADD FILEGROUP YEARFG4;
  ALTER DATABASE Demo ADD FILEGROUP YEARFG5;
  ALTER DATABASE Demo ADD FILEGROUP YEARFG6;
  -- 下面爲這些文件組添加文件來進行物理的數據存儲
  ALTER DATABASE Demo ADD FILE (NAME = 'YEARF1', FILENAME = 'C:/ADVWORKSF1.NDF') TO FILEGROUP YEARFG1;
  ALTER DATABASE Demo ADD FILE (NAME = 'YEARF2', FILENAME = 'C:/ADVWORKSF2.NDF') TO FILEGROUP YEARFG2;
  ALTER DATABASE Demo ADD FILE (NAME = 'YEARF3', FILENAME = 'C:/ADVWORKSF3.NDF') TO FILEGROUP YEARFG3;
  ALTER DATABASE Demo ADD FILE (NAME = 'YEARF4', FILENAME = 'C:/ADVWORKSF4.NDF') TO FILEGROUP YEARFG4;
  ALTER DATABASE Demo ADD FILE (NAME = 'YEARF5', FILENAME = 'C:/ADVWORKSF5.NDF') TO FILEGROUP YEARFG5;
  ALTER DATABASE Demo ADD FILE (NAME = 'YEARF6', FILENAME = 'C:/ADVWORKSF6.NDF') TO FILEGROUP YEARFG6;
  -- HERE WE ASSOCIATE THE PARTITION FUNCTION TO
  -- THE CREATED FILEGROUP VIA A PARTITIONING SCHEME
  USE DEMO;
  GO
  -------------------------------------------------------
  -- 創建分區函數
  -------------------------------------------------------
  CREATE PARTITION FUNCTION YEARPF(datetime)
  AS
  RANGE LEFT FOR VALUES ('01/01/2000'
   ,'01/01/2001'
   ,'01/01/2002'
   ,'01/01/2003'
   ,'01/01/2004')
  -------------------------------------------------------
  -- 創建分區架構
  -------------------------------------------------------
  CREATE PARTITION SCHEME YEARPS
  AS PARTITION YEARPF TO (YEARFG1, YEARFG2,YEARFG3,YEARFG4,YEARFG5,YEARFG6)
  -- 創建使用此Schema的表
  CREATE TABLE PARTITIONEDORDERS
  (
  ID INT NOT NULL IDENTITY(1,1),
  DUEDATE DATETIME NOT NULL,
  ) ON YEARPS(DUEDATE)
  --爲此表填充數據
  declare @DT datetime
  SELECT @DT = '1999-01-01'
  --start looping, stop at ending date
  WHILE (@DT <= '2005-12-21')
  BEGIN
   INSERT INTO PARTITIONEDORDERS VALUES(@DT)
   SET @DT=dateadd(yy,1,@DT)
  END
  -- 現在我們可以看一下我們剛纔插入的行都分佈在哪個Partition
  SELECT *, $PARTITION.YEARPF(DUEDATE) FROM PARTITIONEDORDERS
  --我們可以看一下我們現在PARTITIONEDORDERS表的數據存儲在哪此partition中,以及在這些分區中數據量的分佈
  SELECT * FROM SYS.PARTITIONS WHERE OBJECT_ID = OBJECT_ID('PARTITIONEDORDERS')
  --
  --現在我們設想一下,如果我們隨着時間的流逝,現在已經到了2005年,按照我們先前的設定,我們想再想入一個分區,這時是不是重新創建表分區架構然後重新把數據導放到新的分區架構呢,答案是完全不用。下面我們就看如果新加一個分區。
  --更改分區架構定義語言,讓下一個分區使用和現在已經存在的分區YEARFG6分區中,這樣此分區就存儲了兩段partition的數據。
  ALTER PARTITION SCHEME YEARPS
  NEXT USED YEARFG6;
  --更改分區函數
  ALTER PARTITION FUNCTION YEARPF()
  SPLIT RANGE ('01/01/2005')
  --現在我們可以看一下我們剛纔插入的行都分佈在哪個Partition?
  SELECT *, $PARTITION.YEARPF(DUEDATE) FROM PARTITIONEDORDERS
  --我們可以看一下我們現在PARTITIONEDORDERS表的數據存儲在哪此partition中,以及在這些分區中數據量的分佈
  SELECT * FROM SYS.PARTITIONS WHERE OBJECT_ID = OBJECT_ID('PARTITIONEDORDERS')

------------------------------------------------------------------------------------------------------------------

這就是對數據庫的橫向分割,把一個大表表分割成不同的小表,並把小表並分步到不同的物理文件(由不同的物理磁盤構成)組上。這是做海量數據查詢的基礎理論,sql2000以前不支持這個技術,不過有個分區視圖有類似的功能。但是sql2005直接有這個功能,我想ax應該很快會支持這個功能。

  其實,googl的查詢原理也是這樣的,它把每次查詢同時提交給googl的50萬臺服務器,每個服務器上只保留了不多的信息,這個每個服務器能很快的返回自己找到的數據,並提供給集羣服務器整理排序後顯示給用戶。理論上講,若有經濟條件,把數據分割成無限多個節點,這樣每個節點查詢自己的數據時的速度幾乎是不耗時的,這樣速度就會大大的加快。

<script></script>

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