17 | 如何正确地显示随机消息

86 阅读1分钟

直接使用order by rand()

比如这个语句:select word from words order by rand() limit 3;

image.png 这个语句需要Using temporary 和 Using filesort,查询代价较大:需要临时表,并且需要在临时表上排序。

  • Using temoporary:表示需要使用临时表
  • Using filesort:需要执行排序操作

随机排序的方法

如果只是取1个word值,如果主键id是自增主键:

  1. 取出最大主键M和最小主键N
  2. 用随机函数生成一个最大值到最小值之间的数X=N+(M-N)*rand();
  3. 取不小于X的第一个ID的值(为了防止缺失,所以取数逻辑是 where id >=X limit 1)

问题:ID中间可能有空洞,导致每行被选中的概率不同。比如表中id只有1,2,4,5,那么id=4这一行命中的概率是其他数字的两倍。

另外一种随机排序的方法

  1. 取整个表的行数,记为C。
  2. 取得 Y = floor(C * rand()),floor 函数在这里的作用,就是取整数部分。
  3. 再用 limit Y,1 取得一行。

这个随机算法,避免了上一个随机算法的概率不均匀的问题。

分析:

  • 第1步获取C,需要扫描C行
  • 第3步,扫描Y+1行。MySQL处理limitY,1 的做法需要按顺序一个一个读出来,丢掉前Y个,然后把下一个记录作为返回结果,因此这一步需要扫描Y+1行。
  • 总共需要扫描C+Y+1行,成本比之前的随机排序算法高一些。
  • 但是和order by rand()代价小很多。