sql - 如何使用种子置换 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
变量进行异或。我什至在寻找正确的方向吗?是否有任何我应该考虑但我可能不知道的性能注意事项?
解决方案
ORDER BY HASHBYTES('MD2', e.Title + convert(nvarchar(max), @seed))
应该可以工作,但在性能方面,这将是一场灾难。您每次都会为所有记录计算 MD2。我根本不会在服务器端这样做。您可以在客户端生成随机序列,然后从服务器行中选择行号为 158、7、1027 和 9 的行。但它仍然存在两个问题
- 如果 item 被删除,则所有连续记录的行号都会移动。它只会打破整个序列,你会得到重复和丢失的记录
- 数百万条记录的行数也不是那么快
我看到两个选项。您可以从表中查询所有 id 并将它们用于生成随机顺序。但这将是很多数字。或者你必须确保 id 空间足够密集。然后您可以查询 20 个随机 id,并希望其中至少存在 10 个。如果你运气不好,你将不得不再次查询。
推荐阅读
- android - 如何在没有剪切和拉伸的情况下设置自定义评分栏的高度和宽度。
- vb.net - 如何在 Visual Basic 中忽略区分大小写?
- c++ - 在我的程序中包含 ntddk.h 和 wdm.h 时出现 100 个错误
- java - 如何使用 Selenium 测试网站上的每个链接
- python - 编写程序在特定位置插入数组中的元素不要使用python中的任何函数
- opengl - GL_SRGB_ALPHA 的 10 位替代品?
- c++ - 从驱动程序创建一个 .h 文件,以便能够在 C++ 中使用驱动程序函数
- c# - DefaultIfEmpty().Max() 仍然抛出“序列不包含元素。”
- java - 使用实例类调用 staic 方法(LocalDate
- android - java.lang.IllegalStateException:RecyclerView 正在计算布局时无法调用此方法