【问题标题】:SQL Server Partially Random ResultsSQL Server 部分随机结果
【发布时间】:2014-08-04 07:03:00
【问题描述】:

我正在尝试找出一种方法,从当前有 129,503 条记录的表中随机抽取 X 条记录,并且定期添加更多记录,但需要注意的是我需要对它们进行分页,最好是在数据库级别。使用newid() 将不起作用,因为无法分页该结果集,因为它每次都会更改,也不能使用TABLESAMPLE,因为它不会每次都返回有保证的记录集。我的一个想法是可能生成一个随机值(即newid()),该值存储在此处的每条记录中,因此我可以通过它进行初始排序(而不是动态生成它),然后在这些结果中进行分页始终如一的方式有点超出我的范围。

请考虑一下,因为我需要向访问我们网站的每个用户显示该表中的一组记录,但希望每个用户有不同的视图(使其看起来好像是随机的),但随后需要可靠的分页为每个用户处理这些记录,这样它们就不会得到上一页已经看到的结果。

这是使用 SQL Server 2012,所以有什么想法吗?

【问题讨论】:

  • 桌子有多大?对于一张小桌子,这当然是可行的。如果您负担不起对每个查询进行整体排序,那就更难了。
  • 在我写这篇文章时有 129,503 行,现在是 129,510。所以它每隔一小时左右就会添加一些东西。
  • 这个查询多久执行一次?可以让它运行 100 毫秒吗?如果是,您可以为每次执行对所有行进行排序。

标签: sql sql-server random pagination sql-server-2012


【解决方案1】:

如果我理解正确,你有一个棘手的问题。您希望每个用户有一组不同的记录,并且希望在多个 SQL 调用之间保持顺序。而且,表格的大小可能会在调用之间发生变化。

一种简单的方法是枚举记录。然后,就让每个用户从不同的偏移量开始:

declare @offset int;

select @offset = rand() * count(*)
from table t;

with data as (
      select t.*, row_number() over (order by id) as rn,
             count(*) over () as numrecs
      from table t
     )
select t.*
from table t
order by mod(rn + @offset, numrecs);

然后,您可以使用具有乘法因子和偏移量的伪随机数生成器来增强它。最简单的方法是:

declare @offset int;

select @offset = rand(checksum(newid())) * count(*),
       @factor = rand(checksum(newid())) * count(*)
from table t;

with data as (
      select t.*, row_number() over (order by id) as rn,
             count(*) over () as numrecs
      from table t
     )
select t.*
from table t
order by mod(@factor * rn + @offset, numrecs);

如果@factor 的值是素数会更安全。 @factornumrecs 的偶尔组合可能会导致结果出现小循环。但是看看这是否满足您的需求。

【讨论】:

  • 我们在任何给定时间都有 20 个独立访问者的平均值,所以我担心这个会变得粗糙 - 特别是如果 @factor 应该是质数。当我说独特时,我的意思是在观看谷歌分析时,我们可以看到访问该网站的人在 20 处保持相当稳定,但我们会看到它下降到 18,然后跳到 22,等等。这是一个面向公众的网站,所以用户数量可能相当大。
  • 这近似于随机性,因为所有用户仍然看到相同的总订单,只是起点不同。不确定是否可以接受。
  • @usr 。 . .第一个只是从不同的偏移量开始。第二个从具有不同步骤的不同偏移量开始。这应该是足够随机的。
【解决方案2】:

现在这可能会很慢,因为会有多个函数调用,但您可以尝试:

ORDER BY HASHBYTES('SHA1', UserName + PrimaryKey), PrimaryKey

这个想法分为三个部分。首先,HASHBYTES 产生一致的随机输出。其次,在散列中包含 UserName 意味着每个用户将看到不同的列表。使用主键也意味着每一行都将被唯一且一致地标识。如果发生意外的哈希冲突,我们也只按 PrimaryKey 排序。 您可以使用除 SHA1 之外的不同哈希函数。我不熟悉不同的哈希函数,但我相信 SHA1 会很快。为了安全和存储密码,这不是很好,但对于订购它应该没问题。

【讨论】:

  • 我们不一定有网站的这个特定部分的用户名(它是面向公众的),但我可以很容易地替换在会话启动时生成的 GUID 来处理这个问题我。我有另一个想法要先玩,如果这不起作用,我会在下一个尝试。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-27
  • 2017-01-17
  • 2017-08-29
  • 1970-01-01
  • 1970-01-01
  • 2010-09-05
相关资源
最近更新 更多