我知道如果我运行此查询
select top 100 * from mytable order by newid()
它将从我的表中获得100条随机记录。
但是,由于我在newid()
列表中没有看到select
,我对其工作方式感到有些困惑。谁能解释一下?这里有newid()
的特别之处吗?
答案 0 :(得分:33)
我知道NewID()的作用,我只是 试图了解它会如何帮助 在随机选择中。是那个吗 (1)select语句将选择 来自mytable的一切,(2)每个 排选,大头钉 由NewID()生成的uniqueidentifier, (3)按行对行进行排序 uniqueidentifier和(4)挑选 排序列表中的前100名?
是。这几乎完全正确(除了它不一定需要排序所有行)。您可以通过查看实际执行计划来验证这一点。
SELECT TOP 100 *
FROM master..spt_values
ORDER BY NEWID()
计算标量运算符为每一行添加NEWID()
列(在我的示例查询中的表中为2506),然后表中的行按此列排序,并选择前100行。
SQL Server实际上不需要从位置100向下排序整个集合,因此它使用TOP N
排序运算符,它尝试在内存中执行整个排序操作(for small values of N
)
答案 1 :(得分:10)
一般来说,它的工作原理如下:
答案 2 :(得分:7)
这里的关键是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
此查询背后的基本思想是,我们要为表中的每一行生成0到99之间的随机数,然后选择随机数小于指定百分比值的所有行。在这个例子中,我们希望随机选择大约10%的行;因此,我们选择随机数小于10的所有行。
答案 3 :(得分:4)
答案 4 :(得分:1)
使用select top 100 randid = newid(), * from mytable order by randid
你会被澄清..
答案 5 :(得分:0)
我有一个不重要的查询,该查询使用newId()并连接了许多表。它在大约3秒钟内返回大约1万行。因此,在性能不太差且影响不大的情况下,newId()可能还可以。但是,newId()对大型表不利。
这是布伦特·奥扎尔(Brent Ozar)的博客-https://www.brentozar.com/archive/2018/03/get-random-row-large-table/的解释。
在上面的链接中,我总结了可用于生成随机ID的方法。您可以阅读博客以了解更多详细信息。
从大型表格中获取随机行的4种方法:
有关方法3的更多信息 获取表中的顶部ID字段,生成一个随机数,然后查找该ID。对于前N行,请在N次以下调用该代码,或生成N个随机数并在IN子句中使用。
/* Get a random number smaller than the table's top ID */
DECLARE @rand BIGINT;
DECLARE @maxid INT = (SELECT MAX(Id) FROM dbo.Users);
SELECT @rand = ABS((CHECKSUM(NEWID()))) % @maxid;
/* Get the first row around that ID */
SELECT TOP 1 *
FROM dbo.Users AS u
WHERE u.Id >= @rand;