“洗牌”数据库记录表的最佳方法是什么?

问题描述 投票:0回答:4

假设我有一个包含一堆记录的表,我想将其随机呈现给用户。我还希望用户能够来回分页,所以我必须保留某种顺序,至少在一段时间内。

该应用程序基本上只是 AJAX,并且它对已访问的页面使用缓存,因此即使我总是提供随机结果,当用户尝试返回时,他将获得上一个页面,因为它将从本地缓存加载。

问题是,如果我只返回随机结果,可能会出现一些重复。每个页面包含 6 个结果,因此为了防止出现这种情况,我必须执行类似

WHERE id NOT IN (1,2,3,4 ...)
的操作,将所有先前加载的 ID 放入其中。

该解决方案的巨大缺点是无法在服务器端缓存任何内容,因为每个用户都会请求不同的数据。

替代解决方案可能是创建另一列来对记录进行排序,并每隔在此处插入时间单位对其进行洗牌。这里的问题是,我需要为表中的每条记录设置序列中的随机数,这将需要与记录一样多的查询。

我正在使用 Rails 和 MySQL(如果有相关的话)。

mysql ruby-on-rails database random
4个回答
7
投票

试试这个:

mysql> create table t (i int);
mysql> insert into t values (1),(2),(3),(4),(5),(6);
mysql> select * from t order by rand(123) limit 2 offset 0;
+------+
| i    |
+------+
|    6 | 
|    4 | 
+------+
mysql> select * from t order by rand(123) limit 2 offset 2;
+------+
| i    |
+------+
|    2 | 
|    3 | 
+------+
mysql> select * from t order by rand(123) limit 2 offset 4;
+------+
| i    |
+------+
|    5 | 
|    1 | 
+------+

请注意 rand() 函数有一个种子值 (123)。另请注意,如果重复最后三个查询,每次都会得到相同的结果。


3
投票

如果随机结果是“针对所有人”而不是任何特定用户,那么您可以执行以下操作:(这是针对 Postgres,应该与其他人一起使用)

update mytable set sortorder = random() * 100000000;

select * from mytable order by sortorder, primarykeyid;

由于随机可能会重复,因此通过primarykeyid进行二次排序可以使排序具有一定的稳定性。

您可以根据需要随时执行此操作来刷新缓存。例如,为您的页面提供绝对过期时间,例如每分钟。然后每分钟重新更新排序顺序并正常提供页面。

如果您在刷新窗口收到请求,那么,是的,您有机会让不同的页面获得相同的结果。您还会遇到这样的问题:当他们点击“返回”时,他们很可能无法获得之前的页面(因为它已刷新)。

归结为随机数据呈现背后的动机是什么以及其效果如何。还取决于数据量等

但是这是一种缓存友好的方式来实现这一点,如果这对您很重要的话。它也是无状态的(不需要会话信息)。


2
投票

我会执行以下操作(假设有一个连续的数字主键):

  1. 生成一个随机数并将其存储在用户的会话中
  2. 当用户翻阅数据时,查询总行数
  3. 使用会话中存储的数字作为种子,在每个请求上生成相同的“随机”顺序的 id
  4. 翻阅 id,仅从数据库中检索与这些 id 匹配的记录。

0
投票

SET @rownum := (从 tbl_allindia_mapping 选择 COUNT(1));

SET @row := (SELECT CEIL((RAND() * @rownum)));

选择@行;

从 tbl_allindia_mapping 中选择 *,其中 id = @row;

© www.soinside.com 2019 - 2024. All rights reserved.