SQL Server部分随机结果

时间:2014-06-13 16:37:20

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

我正在试图找出一种方法,从一张表中随机抽出X记录,这些记录目前有129,503条记录,并且定期添加更多记录,但需要注意的是我需要对它们进行分页,最好是在数据库级别。使用newid()将无法正常工作,因为每次更改结果集时都不可能进行分页,也不会使用TABLESAMPLE,因为每次都不会返回有保证的记录集。我有一个想法是可能生成一个随机值(即newid())存储在这里的每个记录上,所以我可以做那个初始排序(而不是动态生成它),然后翻阅那些以一致的方式得出的结果有点超出了我的境界。

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

这与SQL Server 2012有什么想法吗?

2 个答案:

答案 0 :(得分:0)

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

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

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

答案 1 :(得分:0)

如果我理解正确,你会遇到一个很难的问题。您希望每个用户都有一组不同的记录,并且您希望在多个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的组合,这些组合可能会导致结果中出现小周期。但看看这是否符合您的需求。