newid()/ order byは機能しますが、すべての行のIDを生成してからソートする必要があるため、大きな結果セットの場合は非常に負荷がかかります。
TABLESAMPLE()はパフォーマンスの観点からは優れていますが、結果が集中します(ページのすべての行が返されます)。
パフォーマンスの高い真のランダムサンプルの場合、最善の方法は、行をランダムに除外することです。SQL Server Books Onlineの記事「TABLESAMPLEを使用して結果セットを制限する」で次のコードサンプルを見つけました。
個々の行のランダムなサンプルが本当に必要な場合は、クエリを変更して、TABLESAMPLEを使用する代わりに、行をランダムに除外します。たとえば、次のクエリはNEWID関数を使用して、Sales.SalesOrderDetailテーブルの行の約1%を返します。
SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(),SalesOrderID) & 0x7fffffff AS float)
/ CAST (0x7fffffff AS int)
SalesOrderID列はCHECKSUM式に含まれているため、NEWID()は行ごとに1回評価され、行ごとにサンプリングが行われます。式CAST(CHECKSUM(NEWID()、SalesOrderID)&0x7fffffff AS float / CAST(0x7fffffff AS int)は、0と1の間のランダムな浮動小数点値に評価されます。
1,000,000行のテーブルに対して実行すると、次のような結果になります。
SET STATISTICS TIME ON
SET STATISTICS IO ON
/* newid()
rows returned: 10000
logical reads: 3359
CPU time: 3312 ms
elapsed time = 3359 ms
*/
SELECT TOP 1 PERCENT Number
FROM Numbers
ORDER BY newid()
/* TABLESAMPLE
rows returned: 9269 (varies)
logical reads: 32
CPU time: 0 ms
elapsed time: 5 ms
*/
SELECT Number
FROM Numbers
TABLESAMPLE (1 PERCENT)
/* Filter
rows returned: 9994 (varies)
logical reads: 3359
CPU time: 641 ms
elapsed time: 627 ms
*/
SELECT Number
FROM Numbers
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), Number) & 0x7fffffff AS float)
/ CAST (0x7fffffff AS int)
SET STATISTICS IO OFF
SET STATISTICS TIME OFF
TABLESAMPLEを使用しても問題がなければ、最高のパフォーマンスが得られます。それ以外の場合は、newid()/ filterメソッドを使用します。結果セットが大きい場合は、newid()/ order byを最後の手段としてください。