按随机排序时无限滚动中的重复记录

时间:2013-03-05 19:26:39

标签: c# sql-server asp.net-mvc jquery

我有一个无限滚动的网页。我正在为这个卷轴提供随机记录(我正在使用order by newid())。有一个ajax调用,当滚动到达结尾时,它会向页面添加新的随机数据。显然我用这种方法得到了重复的记录。 这是我的问题:有没有办法避免重复记录?我应该存储已加载到页面的某些记录并将其从选择中排除吗?或者我应该选择带有随机记录的大型记录集,将其保存在内存中,然后使用此记录集的块来提供页面?做随机无限滚动的正确方法是什么?提前谢谢!

修改

请求的代码:

数据提供者:

res = data.OrderBy(l => Guid.NewGuid()).Take(numberOfRecords);

客户端:

$.get("/Start/Index/", function (data) {
                if (data != '') {                        
                    isLoading = false;
                    $("#tiles").append(data);});

服务器:

model.PageData = _dataProvider.GetOnePage(recordsPerPage);
return PartialView("_MyView", model.PageData);

2 个答案:

答案 0 :(得分:0)

根据我的理解,对于大型表使用newid并不快 - SqlServer必须在表中的每一行之前为其中的每一行分配一个随机值。这篇MSDN文章有一个小讨论:http://msdn.microsoft.com/en-us/library/cc441928.aspx

要在每次运行查询时获得“相同的随机结果”,您需要计算并存储订单,或者根据您存储的种子使其可预测。

您可以尝试这样的事情:

  SELECT * FROM Table1
  WHERE (ABS(CAST(
  (BINARY_CHECKSUM(*)) as int)) % 100) < 10

BINARY_CHECKSUM函数的一个属性是每次在未修改的行上使用它时,它返回相同的校验和数。因此,当它自己使用时,查询的后续运行返回相同的“随机”行集。通常这是不可取的,但为了您的目的,它可能是。为了使不同用户更随机,您可以通过RAND(?)多个BINARY_CHECKSUM(*)并传入您为该用户会话存储的种子。您还可能希望将BINARY_CHECKSUM中使用的列限制为不可更改的值,例如ID和created_at时间戳,并添加where id&gt;

总而言之,查询可能如下所示:

  SELECT * FROM Table1
  WHERE id > ? AND (ABS(CAST(
  (BINARY_CHECKSUM(*) * RAND(?)) as int)) % 100) < 10

你传递了两个参数:第一次显示无限滚动时的最大ID和你当时生成的种子。

不幸的是,我无法尝试这一点 - 让我知道它是否有效。

答案 1 :(得分:0)

经过2天的研究,我发现在没有重复记录的情况下,没有简单的方法可以进行随机无限滚动。我决定如果我不能做随机滚动我必须做滚动,看起来像随机,但实际上不是。所以最终得到了这个解决方案:

data = data.OrderByDescending(link => EntityFunctions.TruncateTime(link.link_timestamp)).OrderBy(l => l.link_randomid).Skip(skip).Take(numberOfRecords);

其中link_randomid是在记录插入时生成的唯一随机ID。 希望这会为某人节省一些时间。