我知道如果我运行这个查询
select top 100 * from mytable order by newid()
Run Code Online (Sandbox Code Playgroud)
它将从我的表中获得100条随机记录.
但是,我对它是如何工作有点困惑,因为我没有newid()在select列表中看到.谁能解释一下?newid()这里有什么特别的东西吗?
Mar*_*ith 33
我知道NewID()的作用,我只想了解它对随机选择有何帮助.是(1)select语句将从mytable选择一切,(2)选择每一行,使用NewID()生成的uniqueidentifier,(3)按唯一标识符对行进行排序,以及(4)选择顶部100从排序列表?
是.这几乎完全正确(除了它不一定需要对所有行进行排序).您可以通过查看实际执行计划来验证这一点.
SELECT TOP 100 *
FROM master..spt_values
ORDER BY NEWID()
Run Code Online (Sandbox Code Playgroud)
计算标量运算符NEWID()为每行添加列(在我的示例查询中的表中为2506),然后表中的行按此列排序,并选择前100行.
SQL Server实际上不需要从位置100向下排序整个集合,因此它使用TOP N排序运算符,它尝试在内存中执行整个排序操作(对于小值N)
这里的关键是NEWID函数,它在内存中为每一行生成一个全局唯一标识符(GUID).根据定义,GUID是唯一且相当随机的; 因此,当您使用ORDER BY子句对该GUID进行排序时,您将获得表中行的随机排序.取前10%(或任何你想要的百分比)将给你随机抽样表中的行.
提出了NEWID查询; 它很简单,适用于小桌子.但是,当您将NEWID查询用于大型表时,它有一个很大的缺点.ORDER BY子句将表中的所有行复制到tempdb数据库中,并对它们进行排序.这导致两个问题:分拣操作通常具有与之相关的高成本.排序可以使用大量磁盘I/O并可以运行很长时间.在最坏的情况下,tempdb可能会耗尽空间.在最好的情况下,tempdb会占用大量的磁盘空间,如果没有手动收缩命令,它们将永远不会被回收.您需要的是一种随机选择不使用tempdb的行的方法,并且随着表变大而不会慢得多.这是一个关于如何做到这一点的新想法:
SELECT * FROM master..spt_values
WHERE (ABS(CAST(
(BINARY_CHECKSUM(*) *
RAND()) as int)) % 100) < 10
Run Code Online (Sandbox Code Playgroud)
这个查询背后的基本思想是我们想要为表中的每一行生成0到99之间的随机数,然后选择随机数小于指定百分比值的所有行.在这个例子中,我们希望随机选择大约10%的行; 因此,我们选择随机数小于10的所有行.