如何高效随机打乱数据库表行并生成新表?order by random()性能不佳
嘿,我知道用select * from table order by random()来打乱表数据虽然直观,但数据量上去后确实慢得让人头疼——毕竟它得给每一行生成随机值再做全表排序,开销不小。结合你提到的target列分0和1两类的情况,给你几个更高效的解决方案:
方案1:分批次随机排序(针对target分组优化)
如果你的数据库支持窗口函数(比如PostgreSQL、MySQL 8.0+、SQL Server),可以针对target的两类分别打乱,再合并结果。这种方式比全表排序的开销小,而且能保持同类数据内的随机分布:
WITH shuffled_groups AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY target ORDER BY RANDOM()) AS row_rank FROM your_table ) SELECT cst_id, name, salary, fund, age, target FROM shuffled_groups ORDER BY target, row_rank;
要是你不需要按target分组,只是单纯全表打乱,下面这个方案性能更好:
方案2:主键关联随机数,避免全表排序
这个方法绕开了给全表生成随机值后排序的操作,而是先给主键生成随机数,再通过主键关联原表,最后按随机数排序——计算开销会小很多:
SELECT t.* FROM your_table t JOIN (SELECT cst_id, RANDOM() AS rand_val FROM your_table) r ON t.cst_id = r.cst_id ORDER BY r.rand_val;
方案3:直接生成打乱后的新表
既然你最终要生成新表,那可以一步到位,用上面的查询直接创建新表,省去中间步骤:
CREATE TABLE new_shuffled_table AS SELECT t.* FROM your_table t JOIN (SELECT cst_id, RANDOM() AS rand_val FROM your_table) r ON t.cst_id = r.cst_id ORDER BY r.rand_val;
为啥order by random()这么慢?
简单说,random()会给每一行生成一个随机值,数据库随后要对所有这些值做排序操作,这是一个*O(n log n)*的耗时操作——数据量越大,等待时间越长。上面的方案要么缩小了排序的数据集,要么避免了全表排序的额外开销,性能提升会很明显。
内容的提问来源于stack exchange,提问作者Robinson




