mysql - 如何优化 MySQL 的 ORDER BY RAND() 函数?

标签 mysql random performance

我想优化我的查询,所以我查看了 mysql-slow.log

我的大部分慢查询都包含 ORDER BY RAND()。我找不到真正的解决方案来解决这个问题。 MySQLPerformanceBlog 有一个可能的解决方案但我认为这还不够。在优化不佳(或经常更新、用户管理)的表上,它不起作用,或者我需要运行两个或多个查询才能选择 PHP 生成的随机行。

这个问题有解决办法吗?

一个虚拟的例子:

SELECT  accomodation.ac_id,
        accomodation.ac_status,
        accomodation.ac_name,
        accomodation.ac_status,
        accomodation.ac_images
FROM    accomodation, accomodation_category
WHERE   accomodation.ac_status != 'draft'
        AND accomodation.ac_category = accomodation_category.acat_id
        AND accomodation_category.acat_slug != 'vendeglatohely'
        AND ac_images != 'b:0;'
ORDER BY
        RAND()
LIMIT 1

最佳答案

试试这个:

SELECT  *
FROM    (
        SELECT  @cnt := COUNT(*) + 1,
                @lim := 10
        FROM    t_random
        ) vars
STRAIGHT_JOIN
        (
        SELECT  r.*,
                @lim := @lim - 1
        FROM    t_random r
        WHERE   (@cnt := @cnt - 1)
                AND RAND(20090301) < @lim / @cnt
        ) i

这在 MyISAM 上特别有效(因为 COUNT(*) 是即时的),但即使在 InnoDB 中它也是 10 倍于 ORDER BY RAND() 的效率。

这里的主要思想是我们不排序,而是保留两个变量,计算当前步骤中要选择的一行的运行概率

更多详情请参阅我博客中的这篇文章:

更新:

如果你只需要选择一条随机记录,试试这个:

SELECT  aco.*
FROM    (
        SELECT  minid + FLOOR((maxid - minid) * RAND()) AS randid
        FROM    (
                SELECT  MAX(ac_id) AS maxid, MIN(ac_id) AS minid
                FROM    accomodation
                ) q
        ) q2
JOIN    accomodation aco
ON      aco.ac_id =
        COALESCE
        (
        (
        SELECT  accomodation.ac_id
        FROM    accomodation
        WHERE   ac_id > randid
                AND ac_status != 'draft'
                AND ac_images != 'b:0;'
                AND NOT EXISTS
                (
                SELECT  NULL
                FROM    accomodation_category
                WHERE   acat_id = ac_category
                        AND acat_slug = 'vendeglatohely'
                )
        ORDER BY
                ac_id
        LIMIT   1
        ),
        (
        SELECT  accomodation.ac_id
        FROM    accomodation
        WHERE   ac_status != 'draft'
                AND ac_images != 'b:0;'
                AND NOT EXISTS
                (
                SELECT  NULL
                FROM    accomodation_category
                WHERE   acat_id = ac_category
                        AND acat_slug = 'vendeglatohely'
                )
        ORDER BY
                ac_id
        LIMIT   1
        )
        )

这假设您的 ac_id 分布或多或少是均匀的。

关于mysql - 如何优化 MySQL 的 ORDER BY RAND() 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1244555/

相关文章:

php - 在请求其他数据时检索数据库信息

mysql - 返回下个月的行,MYSQL

java - 在 1-49 范围内生成 5 组 6 个随机数,确保每组中没有重复项?

python - 生成总和等于 0 的 N 个随机单位向量(Python)

c++ - boost.random buggy 警告 - 这是什么意思?

java - 这是准确的性能测试吗?

php - 使用 PHP 将用户输入的全文搜索查询解析为 MySQL 的 WHERE 子句

mysql - apache/mysql 响应缓慢但未达到 cpu/内存和限制

c++ - 是什么让 STL 如此之快?

MySQL - 使用子查询求平均值