RAND 与 random 是什么
MySQL 的 RAND() 与 PostgreSQL 的 random() 返回 0 到 1 之间的浮点随机数。需要可复现的序列时,MySQL 用 RAND(seed) 传种子,PostgreSQL 用 setseed() 设置会话种子。常见用途是随机取一条记录、随机抽样与造测试数据。性能陷阱也很集中:对列逐行调用随机函数会让每行重新求值,写在 WHERE 或 ORDER BY 里无法使用索引,大表上代价很高。
基本信息
| MySQL | RAND([seed]) 返回 0 到 1 的浮点,传种子后同一会话内可复现 |
|---|---|
| PostgreSQL | random() 返回 double precision,用 SELECT setseed(0.5) 设置会话种子 |
| 排序代价 | ORDER BY RAND() / random() 需要为全部行求值并排序 |
| 抽样代价 | WHERE RAND() < p 逐行求值,索引失效 |
| 大表采样 | PostgreSQL 可用 TABLESAMPLE;MySQL 无该语法,宜用主键范围随机 |
典型使用场景
- 随机取一条记录:抽奖、相关推荐、随机文案
- 随机抽样做探索性数据分析
- 生成测试数据时制造随机取值
- 打乱输出顺序(仅在结果集较小时使用)
- A/B 分桶的辅助手段(稳定分流更推荐按 id 取模)
MySQL 用法
MySQL 用法
-- 随机取一行:小表可用,大表代价高(需要排序全部行)
SELECT * FROM articles ORDER BY RAND() LIMIT 1;
-- 随机抽样:WHERE 里逐行求值,且无法使用索引
SELECT * FROM users WHERE RAND() < 0.1 LIMIT 1000;
-- 可复现的随机序列(同一会话内)
SELECT RAND(42) AS r1, RAND() AS r2; # 种子固定后,后续 RAND() 依次可复现PostgreSQL 用法
PostgreSQL 用法
-- 随机取行与按概率抽样
SELECT * FROM articles ORDER BY random() LIMIT 1;
-- 大表采样:按数据块采样,代价远低于随机排序
SELECT * FROM big_table TABLESAMPLE SYSTEM (1); -- 约 1% 的块
SELECT * FROM big_table TABLESAMPLE BERNOULLI (1); -- 按行采样,约 1% 的行
-- 让随机序列可复现(会话级)
SELECT setseed(0.5);
SELECT random() AS r;用法与代价
| 用法 | 写法 | 代价或注意点 |
|---|---|---|
| 随机取一行 | ORDER BY RAND()/random() LIMIT 1 | 需要为全部行求值并排序 |
| 按概率抽样 | WHERE RAND() < 0.1 | 逐行求值,索引失效 |
| 稳定分桶 | MOD(id, n) | 结果可复现,适合 A/B 分流 |
| 大表采样 | PostgreSQL TABLESAMPLE | MySQL 无该语法,可用主键范围随机 |
需要可复现的随机结果时,MySQL 用 RAND(seed)、PostgreSQL 用 setseed();但序列结果仍依赖执行顺序,多线程或分布式场景下不一定稳定复现。
ORDER BY RAND() LIMIT 1 在大表上等于把全表随机排序:数据量大时非常慢。可行的替代是先按主键范围随机定位几行,再从候选里挑一条。