“newid()的命令” - 它是如何工作的?

时间:2011-02-12 18:27:28

标签: sql-server newid

我知道如果我运行此查询

select top 100 * from mytable order by newid()

它将从我的表中获得100条随机记录。

但是,由于我在newid()列表中没有看到select,我对其工作方式感到有些困惑。谁能解释一下?这里有newid()的特别之处吗?

6 个答案:

答案 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

Plan

答案 1 :(得分:10)

一般来说,它的工作原理如下:

  • mytable 中的所有行都是“循环播放”
  • 每行执行NEWID()
  • 行根据NEWID()
  • 中的随机数排序
  • 选择了第一行

答案 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)

正如MSDN所说:

  

NewID()创建唯一的type值   唯一标识符

,您的表格将按此随机值排序。

答案 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种方法:

  1. 方法1,效果不佳:ORDER BY NEWID()>性能不佳!
  2. 方法2,更好却奇怪:TABLESAMPLE>很多陷阱并并非真的 随机!
  3. 方法3,最佳,但需要代码:随机主键> 最快,但不适用于负数。
  4. 方法4,OFFSET-FETCH(2012+)>仅适用于群集 索引。

有关方法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;