order by rand() 性能极差是因为mysql必须全表扫描、为每一行调用rand()并执行filesort,导致cpu和i/o双爆;即使limit 1,仍需处理全部数据,索引完全失效,explain显示type: all和using temporary; using filesort。

因为 ORDER BY RAND() 强制 MySQL 对**每一行都调用一次 RAND() 函数 + 全表排序(filesort)**,哪怕只要 1 条记录,也得扫完整张表、生成全部随机数、写临时表、磁盘排序——CPU 和 I/O 双爆,不是“有点慢”,是“数据量翻倍,耗时翻十倍”。
为什么一用就 CPU 100%?
根本不是随机函数本身慢,而是执行模型不可扩展:
-
EXPLAIN显示type: ALL(全表扫描),Extra: Using temporary; Using filesort—— 这两个标志同时出现,就是性能雪崩的前兆 - 每行都要计算
RAND(),100 万行 = 100 万次浮点运算,纯 CPU 消耗 - 排序必须把所有行+随机值塞进临时内存;超限就落盘,触发大量磁盘随机读写
- 并发高时,多个查询争抢
sort_buffer_size,互相阻塞,连接池迅速被占满
常见误判:加索引、换引擎、调缓存都没用
这些操作对 ORDER BY RAND() 完全无效,原因很直接:
- 索引只加速查找,不加速“为每行算随机数 + 排序”,优化器直接放弃使用任何索引
-
InnoDB和MyISAM表表现一致,引擎无关 -
RAND(1)带种子?只保证结果可重现,不减少计算量 - Query Cache(如果还开着)完全失效,因为
RAND()是非确定性函数
真实线上症状:别等报警才发觉
不是“查得慢”,是整库被拖垮:
-
SHOW PROCESSLIST里大量线程卡在Sorting result或Copying to tmp table on disk - 监控看到
Sort_merge_passes暴涨,Created_tmp_disk_tables持续上升 - 慢查询日志里反复出现同一句
ORDER BY RAND(),但 LIMIT 很小(比如LIMIT 3) - 砍掉这句 SQL 后,CPU 负载瞬间从 95% 掉到 15%,页面响应从 8s 回落到 200ms
真正要盯住的硬伤:它根本不适合在线服务
哪怕你只抽 1 条中奖用户,MySQL 也得把整张用户表翻一遍。这不是配置问题,是语义缺陷 —— RAND() 让整个查询逻辑无法剪枝、无法提前终止、无法利用索引定位。所以阿里 DBA 规范里那句【强制禁用】不是吓唬人,是血泪教训堆出来的红线。别想着“我表才 50 万,应该还好”,50 万行下 ORDER BY RAND() 已经稳定在 3–5 秒,而替代方案(如主键范围抽样)始终在 0.02 秒内,差了两个数量级。真正麻烦的从来不是“怎么写”,而是“什么时候意识到不能这么写”。











