首页 > 解决方案 > 如何使用种子置换 SQL 表?

问题描述

背景

我有一个带有无限滚动项目列表的前端,我通过指定页面限制和偏移量来获取项目页面。

问题

除了简单地按某些列排序结果之外,我还想添加一个“随机”选项。问题是,我不想要重复,所以我需要在进行限制和偏移之前对整个数据集进行排列,并且只要我提供相同的种子,我就需要能够获得相同的排列。

我试过的

一种天真的方法是编写一个表值函数,它接受一个int种子并在ORDER BY子句中使用它,如下所示:

SELECT *
FROM dbo.Entities e
ORDER BY HASHBYTES('MD2', e.Title) ^ @seed
OFFSET 0 ROWS
FETCH NEXT (SELECT COUNT(*) FROM dbo.Entities) ROWS ONLY

乍一看,这似乎效果很好,但事实证明,由于缺少更好的词,它并不是很“不稳定”——它在稀疏的结果集中变得更加明显,其中大多数种子(从 0 到 2147483647 之间随机选择)产生相同的顺序。

我认为通过散列种子也可以获得更好的结果,但是 SQL Server 不允许我对两个varbinary变量进行异或。我什至在寻找正确的方向吗?是否有任何我应该考虑但我可能不知道的性能注意事项?

标签: sqlsql-servertsql

解决方案


ORDER BY HASHBYTES('MD2', e.Title + convert(nvarchar(max), @seed))

应该可以工作,但在性能方面,这将是一场灾难。您每次都会为所有记录计算 MD2。我根本不会在服务器端这样做。您可以在客户端生成随机序列,然后从服务器行中选择行号为 158、7、1027 和 9 的行。但它仍然存在两个问题

  • 如果 item 被删除,则所有连续记录的行号都会移动。它只会打破整个序列,你会得到重复和丢失的记录
  • 数百万条记录的行数也不是那么快

我看到两个选项。您可以从表中查询所有 id 并将它们用于生成随机顺序。但这将是很多数字。或者你必须确保 id 空间足够密集。然后您可以查询 20 个随机 id,并希望其中至少存在 10 个。如果你运气不好,你将不得不再次查询。


推荐阅读