从SQL Server表中选择n个随机行

我有一个大约有50,000行的SQL Server表。 我想随机选择约5000个这样的行。 我想到了一个复杂的方法,用一个“随机数”列创建一个临时表,将我的表复制到该表中,循环遍历临时表并使用RAND()更新每一行,然后从该表中选择随机数列<0.1。 如果可能的话,我正在寻找一种更简单的方法来做到这一点。

本文建议使用NEWID()函数。 这看起来很有希望,但我看不出我如何可靠地选择一定比例的行。

有人曾经这样做过? 有任何想法吗?


select top 10 percent * from [yourtable] order by newid()

为了回应关于大型表格的“纯垃圾”评论:你可以这样做来提高性能。

select  * from [yourtable] where [yourPk] in 
(select top 10 percent [yourPk] from [yourtable] order by newid())

这些成本将成为价值加上联合成本的关键扫描,在具有小百分比选择的大型表上应该是合理的。


根据您的需求, TABLESAMPLE将为您带来几乎随机和更好的性能。 这在MS SQL Server 2005和更高版本中可用。

TABLESAMPLE将从随机页面而不是随机行返回数据,因此甚至不会检索不会返回的数据。

在我测试的一张非常大的桌子上

select top 1 percent * from [tablename] order by newid()

花了20多分钟。

select * from [tablename] tablesample(1 percent)

花了2分钟。

对于TABLESAMPLE较小样本,性能也会提高,但不会与newid()

请记住,这不像newid()方法那样随机,但会给你一个体面的抽样。

请参阅MSDN页面。


newid()/ order by将会起作用,但对于大型结果集来说会非常昂贵,因为它必须为每一行生成一个id,然后对它们进行排序。

从性能的角度来看,TABLESAMPLE()是很好的,但是你会得到结果的聚合(页面上的所有行都会被返回)。

为了获得更好的真实随机样本,最好的方法是随机过滤行。 我在SQL Server联机丛书文章中使用TABLESAMPLE限制结果集中找到以下代码示例:

如果您确实需要单个行的随机样本,请修改您的查询以随机筛选出行,而不是使用TABLESAMPLE。 例如,以下查询使用NEWID函数返回Sales.SalesOrderDetail表的大约百分之一行:

SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(),SalesOrderID) & 0x7fffffff AS float)
              / CAST (0x7fffffff AS int)

SalesOrderID列包含在CHECKSUM表达式中,因此NEWID()每行评估一次以实现每行的采样。 表达式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()/过滤器方法。 如果你有一个大的结果集,newid()/ order by应该是最后的手段。

链接地址: http://www.djcxy.com/p/94245.html

上一篇: Select n random rows from SQL Server table

下一篇: How to update a column fetched by a cursor in TSQL