搜尋本站文章

2011-04-16

認識 TABLESAMPLE 子句;快速從大型資料表傳回取樣的資料列

當下列其中一項條件成立時,就可以使用 TABLESAMPLE 快速從大型資料表傳回取樣。
(1) 該取樣在個別資料列層級不需是真正的隨機取樣。
(2) 在資料表個別頁面上的資料列未與相同頁面上的其他資料列相互關聯。

請注意,取樣的對象是「頁面(Pages)」。
在 SQL Server 中,分頁大小為 8 KB。這意味著 SQL Server 資料庫是每 MB 有 128 個分頁。
每個分頁的開頭為 96 個位元組的標頭,用來儲存與分頁有關的系統資訊。
此資訊包括頁碼、分頁類型、分頁上可用空間的數量,以及擁有分頁的物件配置單位識別碼。

如果您真的想要個別資料列的隨機取樣,請將查詢修改為隨機篩選出資料列,而不是使用 TABLESAMPLE。例如,搭配使用 NEWID 函數。

TABLESAMPLE 子句會將 FROM 子句中資料表所傳回的資料列數限制為取樣數目或是資料列的 PERCENT。

TABLESPACE 子句的語法如下:
TABLESAMPLE [SYSTEM] (sample_number [ PERCENT | ROWS ] )
[ REPEATABLE (repeat_seed) ]

注意事項:
(1)TABLESAMPLE 不能套用至衍生資料表、連結的伺服器之資料表以及從資料表值函式、資料列集函數或是 OPENXML 所衍生的資料表。
(2)TABLESAMPLE 無法在檢視的定義中或是在嵌入資料表值函式中指定。
(3)TABLESAMPLE 已在 SQL Server 2005 中推出。當您針對從舊版升級的資料庫使用 TABLESAMPLE 時,資料庫的相容性層級至少必須設定為 90。

(一) 使用 SYSTEM 選項
SYSTEM 可指定 ANSI SQL 實作相依的取樣方法。指定 SYSTEM 雖然是選擇性的,但此選項卻是 SQL Server 中唯一可使用的取樣方法,而且預設會套用它。

TABLESAMPLE SYSTEM 會傳回資料列數的近似百分比,並會為資料表中每 8 KB 的實體頁產生隨機值。
根據某頁中的隨機值以及查詢中所指定的百分比,在取樣中包含或排除某頁。

所包含的每頁會傳回取樣結果集中的所有資料列。例如,當指定 TABLESAMPLE SYSTEM 10 PERCENT 時,SQL Server 會傳回資料表之指定資料頁約 10% 的資料列。
如果資料列平均分配在資料表的各頁上,而且如果資料表中有足夠的頁數,則傳回的資料列數目應該近似於要求的取樣大小。

然而,由於針對每頁所產生的隨機值與針對任何其他頁所產生的值無關,因此有可能會傳回比要求的百分比較大或較小的頁數百分比。
TOP(n) 運算子可用以將資料列的數目限制成指定的最大值。

當指定資料列數目而不是資料表中資料列總數的百分比時,會將該數目轉換成資料列數的百分比,因此應該會傳回頁數。
接著會使用該計算出的百分比來執行 TABLESAMPLE 作業。

如果資料表是由單一頁所組成,則會傳回該頁的所有資料列或是沒有任何資料列傳回。
在此情況下,不論該頁的資料列數為何,TABLESAMPLE SYSTEM 都只能傳回該頁之資料列的 100% 或 0%。

對於指定資料表使用 TABLESAMPLE SYSTEM,將限制執行計畫對於該資料表使用資料表掃描 (堆積的掃描或是叢集索引 (如果有的話) 的掃描)。
雖然該計畫顯示執行了資料表掃描,但只有那些包含在結果集中的頁才真正需要從資料檔中讀取它們。

重要事項:
應該謹慎地使用 TABLESAMPLE SYSTEM 子句,並對使用取樣的含義有相當程度的瞭解。

例如,兩個資料表的聯結有可能會同時傳回兩個資料表中每個資料列相符的資料列;然而,如果為兩個資料表的其中一個指定 TABLESAMPLE SYSTEM,則從未取樣的資料表所傳回的某些資料列就不可能有取樣資料表的相符資料列。

雖然實際上資料是有效的,但這有可能會使您懷疑基礎資料表中有資料一致性的問題。
同樣地,如果為聯結的兩個資料表指定 TABLESAMPLE SYSTEM,所發現的問題可能會更糟。

(二)使用 REPEATABLE 選項
REPEATABLE 選項會再傳回一次選取的取樣。

當以相同的 repeat_seed 值指定 REPEATABLE 時,只要資料表未做過任何變更,SQL Server 就會傳回相同的資料列子集。

當以不同的 repeat_seed 值指定 REPEATABLE 時,SQL Server 通常會傳回資料表中資料列的不同取樣。
下列對於資料表所進行的動作將視為變更:插入、更新、刪除、索引重建、索引重組、還原資料庫以及附加資料庫。


請參考以下的範例:
--Production.TransactionHistory 資料表包含 11,3443 個資料列。
SELECT COUNT(*) FROM AdventureWorks2008.Production.TransactionHistory

--EX1. 選取某百分比的資料列
--Production.TransactionHistory 資料表包含 11,3443 個資料列。下列陳述式會傳回約百分之 10 的資料列。傳回的資料列數通常會隨著陳述式的每次執行而改變。
SELECT COUNT(*) FROM AdventureWorks2008.Production.TransactionHistory
TABLESAMPLE (10 PERCENT)

--EX2. 選取數個資料列
-- 下列陳述式會傳回約 1000 個資料列。傳回的實際資料列數可能會有極大的差異。如果指定的數目較小 (例如 5),您可能無法在樣本中收到結果。
SELECT COUNT(*) FROM AdventureWorks2008.Production.TransactionHistory
TABLESAMPLE (1000 ROWS)

-- 使用 SYSTEM 選項:SYSTEM 可指定 ANSI SQL 實作相依的取樣方法。指定 SYSTEM 雖然是選擇性的,但此選項卻是 SQL Server 中唯一可使用的取樣方法,而且預設會套用它。
SELECT COUNT(*) FROM AdventureWorks2008.Production.TransactionHistory
TABLESAMPLE SYSTEM  (1000 ROWS)

--EX3. 以初始值選取某百分比的資料列
-- 下列陳述式會在每次執行時傳回同一組資料列。初始值 10 是任意選擇的值。
SELECT COUNT(*) FROM AdventureWorks2008.Production.TransactionHistory
TABLESAMPLE (10 PERCENT)
REPEATABLE (10) ;

--EX4. 執行 100 次的結果
DECLARE @tb1 TABLE(myrow int IDENTITY(1,1), ctype1 varchar(50), cnt1 int, ctype2 varchar(50), cnt2 int,  ctype3 varchar(50), cnt3 int)
DECLARE @cnt INT=1

WHILE @cnt <101
BEGIN
 INSERT @tb1 VALUES
  ('TABLESAMPLE (10 PERCENT)', (SELECT COUNT(*) FROM AdventureWorks2008.Production.TransactionHistory TABLESAMPLE (10 PERCENT)), 
  'TABLESAMPLE (1000 ROWS)',(SELECT COUNT(*) FROM AdventureWorks2008.Production.TransactionHistory TABLESAMPLE SYSTEM  (1000 ROWS)),
  'TABLESAMPLE (1000 ROWS) REPEATABLE (10)' , (SELECT COUNT(*) FROM AdventureWorks2008.Production.TransactionHistory TABLESAMPLE (10 PERCENT) REPEATABLE (10)) )
 
 SET @cnt +=1
END
SELECT myrow N'編號', ctype1 N'語法 1', cnt1 N'回傳筆數', ctype2 N'語法 2', cnt2 N'回傳筆數',ctype3 N'語法 3', cnt3 N'回傳筆數'
FROM @tb1
請參考下圖所示:


由於取樣的對象是「頁面(Pages)」,每次執行所回傳的筆數都不盡相同。

所包含的每頁會傳回取樣結果集中的所有資料列。例如,當指定 TABLESAMPLE SYSTEM 10 PERCENT 時,SQL Server 會傳回資料表之指定資料頁約 10% 的資料列。
如果資料列平均分配在資料表的各頁上,而且如果資料表中有足夠的頁數,則傳回的資料列數目應該近似於要求的取樣大小。


參考資料:
使用 TABLESAMPLE 限制結果集
http://technet.microsoft.com/zh-tw/library/ms189108.aspx

了解頁面與範圍
http://msdn.microsoft.com/zh-tw/library/ms190969.aspx

Retrieving random data from SQL Server with TABLESAMPLE
http://www.mssqltips.com/tip.asp?tip=1308

Randomly Retrieve SQL Server Records
http://www.mssqltips.com/tip.asp?tip=1009