【问题标题】:Is this a good or bad way of generating random numbers for each record?这是为每条记录生成随机数的好方法还是坏方法?
【发布时间】:2023-03-17 06:40:02
【问题描述】:

我的一位同事在 SQL Server 中发现了一种我不知道的行为。

CREATE VIEW dbo.vRandNumber AS
SELECT RAND() as RandNumber
GO

CREATE FUNCTION dbo.RandNumber() RETURNS float AS
RETURN (SELECT RandNumber FROM vRandNumber)
GO

DECLARE @mytable TABLE (id INT)
INSERT INTO @mytable SELECT 1
INSERT INTO @mytable SELECT 2
INSERT INTO @mytable SELECT 3

SELECT *, dbo.RandNumber() FROM @mytable

似乎是为数据集中的每条记录生成“随机”值的最快方法。但我不完全确定这是记录在案的行为的结果,还是利用了奇怪的巧合。

会使用这样的东西吗?


编辑

这不是关于 RAND() 函数本身优点的问题,而是使用 UDF/VIEW 组合强制它在每一行上重新计算的问题。 (在最终查询中仅使用 RAND(),而不是 dbo.RandNumber(),将为每条记录提供相同的值。)

此外,重点是每次查看时值都不同。例如,启用随机选择记录。

编辑

对于 SQL Server 2000+。

【问题讨论】:

    标签: sql sql-server tsql sql-server-2000 random


    【解决方案1】:

    我不会为我想继续在 SQL Server 的未来版本上工作的软件这样做。我找到了一种从 RAND() 为 select 语句中的每一行返回不同值的方法。这个发现是 1) 有点 hack 和 2) 是在 SQL Server 2005 上进行的。它不再适用于 SQL Server 2008。这种经历让我更加警惕依靠诡计来让 rand() 每返回一个随机值行。

    另外,我相信允许 SQL Server 优化对 UDF 的多次调用......尽管这可能会发生变化,因为它们现在确实允许一些非确定性函数。

    仅适用于 SQL Server 2005,一种强制 rand() 在 select 语句中按行执行的方法。 不适用于 SQL Server 2008。 未在 2005 之前的任何版本上测试:

    create table #t (i int)
    insert into #t values (1)
    insert into #t values (2)
    insert into #t values (3)
    
    select i, case when i = 1 then rand() else rand() end as r
    from #t
    
    1   0.84923391682467
    2   0.0482397143838935
    3   0.939738172108974
    

    另外,我知道您说您不是在询问 rand() 的随机性,但我将提供一个很好的参考:http://msdn.microsoft.com/en-us/library/aa175776(SQL.80).aspx。它将 rand() 与 newid() 和 rand(FunctionOf(PK, current datetime)) 进行比较。

    【讨论】:

    • CHECKSUM(NEWID()) 至少适用于 SQL 2000+。这依赖于可能在 SQL 2005 补丁中删除的特定行为
    【解决方案2】:

    这取决于您需要随机值的用途。这还取决于您需要INTEGERVARCHAR 等中的值的格式。

    如果我需要随机排序行,我会做类似的事情

    SELECT *
    FROM [MyTable]
    ORDER BY newID()
    

    同样,您可以使用 SQL Server 的身份“功能”生成一个ints 表并执行类似的查询,这可能会给您一个随机数。

    我的同事需要每行一个随机整数,因此他在我们的表中添加了一个计算字段,并在查询中返回的每行生成一个随机数(整数)。我不确定我是否推荐这个;它在某些工具中引起了问题,但它为每个表提供了随机整数。然后,我们可以将我的newid() 解决方案与该表结合起来,并在需要时获取一组随机数。

    所以我回到这取决于。你能详细说明你需要什么吗?

    更新:这里是表定义 sn-p 我的同事曾经让计算列在每次查询表时每行返回不同的随机数:

    CREATE TABLE [dbo].[Table](
        -- ...
        [OrderID] [smallint] NOT NULL,  --Not sure what happens if this is null
        -- ...
        [RandomizeID]  AS (convert(int,(1000 * rand(([OrderID] * 100 * datepart(millisecond,getdate())))))),
        -- ...
    )
    

    【讨论】:

    • 目前还是比较学术的,只是一个从记录集中随机获取行的例子。因为每次都需要不同的记录。可能是加权的,但使用 [weight]*dbo.RandNumber() 可以做到这一点。所以简单地说,一种为每条记录获取随机生成的行的方法,每次查询表时都不一样。
    • 我没有指定 sql-2000 兼容,而且(afaik)newID() 也没有返回随机数。它既不是一个数字(例如,用于将权重乘以)也不是真正随机的,因为它是基于时间、硬件等的。但是,我不知道它是否比 RAND() 更随机功能。
    • 你的同事在计算字段中的计算是什么?我刚刚尝试使用 RAND() 并在每次执行时得到不同的值,但每条记录的值相同......
    【解决方案3】:

    如果我必须为 SQL 中的每一行选择一个随机数,并且您可以向我证明 RAND() 正在生成真正的随机数...

    是的。我可能会使用类似的东西。

    【讨论】:

      【解决方案4】:

      我不会用这个。据我所知, RAND() 使用系统时间作为种子,并在彼此快速执行多次时产生相同的值。例如,试试这个:

      SELECT    *, 
                RAND()
      FROM      SomeTable
      

      RAND() 将为每一行提供相同的值。

      【讨论】:

      • 这种行为并不是因为时代的临近。这是因为 RAND() 只执行一次,而不是每条记录执行一次。此示例也使用 RAND(),但在 UDF 和 VIEW 后面都对其进行了混淆。从而迫使它每次都重新计算。在我的示例中,所有三个记录每次都获得不同的值。它们有多随机,我不确定。但它们肯定不会相同(除非偶然)。
      • 我的查询实际上并不是关于 RAND() 的优点,而是使用 UDF/VIEW 组合强制为每一行重新分配的优点。
      • 哦,我明白了。感谢有关 RAND() 的信息,每个记录集只执行一次,我不知道这一点。另外,很抱歉误解了您的问题。
      【解决方案5】:

      视图和 udf 方法对我来说很笨拙:过多的琐碎对象使用有缺陷的功能。

      我会使用CHECKSUM(NEWID()) 生成一个随机数(而不是RAND() * xxx),或者新的SQL Server 2008 CRYPT_GEN_RANDOM

      【讨论】:

      • NEWID() 不会像 RAND() 一样解析为常量吗?那么仍然需要 view/udf 组合吗? (本质上存在问题的是 view/udf 组合,允许为每条记录重新评估通常被视为常量表达式的内容。)
      • NEWID() 是每个调用,而不是每个语句。所以每行会有所不同。
      猜你喜欢
      • 2010-11-01
      • 2013-05-13
      • 2013-03-26
      • 2010-09-23
      • 2017-10-25
      • 1970-01-01
      • 1970-01-01
      • 2015-06-10
      • 2014-06-08
      相关资源
      最近更新 更多