【问题标题】:Consistent random ordering in a MySQL queryMySQL 查询中的一致随机排序
【发布时间】:2011-09-03 21:19:03
【问题描述】:

我有一个图片数据库,我想让访问者浏览图片。我有一个“下一个”和一个“上一个”链接。

但我想要的是向每个访问者展示图片的顺序。我怎样才能做到这一点?如果我使用 ORDER BY RANDOM(),我有时会显示重复的图像。

有人可以帮帮我吗?谢谢!

【问题讨论】:

    标签: mysql random


    【解决方案1】:

    你可以尝试在随机函数中使用种子:

    SELECT something FROM somewhere ORDER BY rand(123)

    123 是种子。 Random 应该返回相同的值。

    【讨论】:

    • 总是返回相同值的函数排序有什么用?
    • 先试一试。您可以为会话范围或其他范围生成种子,并使用它对相同的结果进行分页。
    • 实际上,izi 说得有道理。如果您可以为每个访问者保持此种子的唯一性,它将解决问题。我不知道种子的存在,但它很有趣。
    • @izi,你知道种子出现在哪个版本的 MySQL 中吗?
    • @Wouter,试试这个:CREATE TABLE test (i INT);,然后在表中插入一些值,然后使用SELECT * FROM test ORDER BY RAND(1)。重复此操作,您将以相同的随机顺序看到结果。然后尝试使用RAND(2)
    【解决方案2】:

    问题在于每个页面都会再次运行RAND(),并且无法知道返回的图片之前是否已经返回。您必须以一种可以过滤掉前几页中已经显示的图片的方式来编写查询,这样RAND() 将有更少的选项可供选择。

    一个想法是随机化图片,选择 ID,将 ID 存储在会话中,然后使用这些 ID SELECT。这样一来,每个用户都将随机获得图片,但他们将能够通过它们进行分页,而无需在每个页面上重新随机化它们。

    所以,类似:

    1. SELECT id FROM pictures ORDER BY RAND() LIMIT x 如果您还没有会话中的 ID
    2. 将 ID 存储在会话中
    3. SELECT ... FROM pictures WHERE id IN (IDs from session) LIMIT x

    另一个想法是在会话中存储用户已经看到的 ID 并将它们过滤掉。例如:

    1. SELECT ... FROM pictures ORDER BY RAND() LIMIT x 如果会话不包含任何 ID
    2. 将当前查询中的 ID 附加到会话中
    3. SELECT ... FROM pictures WHERE id NOT IN (IDs from session) ORDER BY RAND() LIMIT x

    正如izi 指出的那样,另一种方法似乎是使用种子。我不得不说我不知道​​种子,但对于完全相同的种子值,它似乎返回完全相同的结果。因此,运行您通常的查询并使用RAND(seed) 而不是RAND(),其中“seed”是唯一的字符串或数字。您可以使用会话 ID 作为种子,因为它保证对每个访问者都是唯一的。

    【讨论】:

    • +1 您似乎是唯一一个理解 OP 所描述的潜在问题的人。实际上,您需要为用户存储会话的顺序,或者如果用户登录,则为用户存储。基本上这不是mysql查询的问题,而是页面请求之间如何保持状态的问题。
    • 这是一个有效的解决方案,但 izi 的答案是一个很多更好的选择。
    • 我同意丹尼斯的观点。似乎这就是种子的用途。
    • 感谢您的回答!如何存储 ID?有数千个 Cookie?
    • @Nathaniel,请使用 izi 的建议。
    【解决方案3】:

    您可以按照 izi 的建议播种随机函数,或者按照 rdineiu 的建议跟踪访问过的图像与未访问过的图像。

    我想强调的是,这两个选项都不会表现良好。要么会导致您使用任意标准对整个表(或感兴趣的部分)进行排序,并提取顶部的n 行,可能带有偏移量。它会非常慢。

    因此,考虑一下每个访问者应该获得不同的图像顺序是多么重要。可能,它不会那么 重要,只要事情看起来随机。假设是这种情况,请考虑这个替代方案......

    在您的表中添加一个额外的float 字段,将其命名为sort_ord在其上添加索引。在每次插入或更新时,为其分配一个随机值。这里的重点是在不影响性能的情况下以看似随机的顺序结束(从访问者的角度来看)。

    这样的设置将允许您获取顶部的n 行并使用索引对图像进行分页,而不是对整个表格进行排序。

    您可以选择让 cron 作业定期设置一个新值:

    update yourtable
    set sort_ord = rand();
    

    您也可以选择创建多个此类字段,并在访问者访问您的网站(cookie 或会话)时为其分配一个。

    【讨论】:

    • Hrm,这意味着 所有 访问者将看到相同的内容...不过话说回来,正如您所说,优先级很重要。如果表只包含几百行,每天有几百名用户访问该站点,并且您需要所有访问者看到不同的东西,那么ORDER BY RAND 将做需要做的事情,而不会看到任何性能问题。
    • 这就是重点,是的:这个想法的核心是他们不会坐在一起,所以他们不会知道他们正在以相同的方式查看图像。
    • 另外,这可能会引入并发问题。如果用户看到第 1 页,则 cron 运行,值将被更改,用户可能会在第 2 页再次看到相同的结果。
    • 确实会在凌晨 4 点运行 cron 作业。作为一名网站设计师,我很乐意忍受这种副作用。 :-)
    • 呵呵,是的,但不幸的是,当你是凌晨 4 点时,对于其他 100 个用户来说很可能是下午 2 点......
    【解决方案4】:

    这将解决:

    SELECT DISTINCT RAND() as rnd, [rest of your query] ORDER BY rnd;
    

    【讨论】:

    • 这是 OP 已经在做的事情。问题可能是每次用户请求页面并且运行您建议的查询时,每一行都会重新编号,因此无论如何您都会得到相同的图像。
    【解决方案5】:

    使用 RAND(SEED)。来自文档:“如果指定了常量整数参数 N,则将其用作种子值。”(http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_rand)。

    在上面的示例中,结果顺序始终相同。您只需更改种子 (351) 即可获得新的随机顺序。

    SELECT * FROM your_table ORDER BY RAND(351);
    

    您可以在每次用户点击第一页时更改种子。

    【讨论】:

      【解决方案6】:

      如果没有看到 SQL,我猜你可以尝试 SELECT DISTINCT...

      【讨论】:

      • 他的意思是SELECT DISTINCT image FROM images ORDER BY RANDOM()
      • 我不喜欢投票,所以我不会那样做。但是这个答案将 OP 发送到错误的方向。
      猜你喜欢
      • 2015-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-13
      • 2016-05-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多