mysql随机数生原理 mysql实现原理和机制

渴望登顶的登山者不会被沿途的足迹所陶醉。1前言如下,我这里有一个问题记录表。
我需要从列表中随机选择4条数据,所以我会这样写(随机排序,取前4条)
执行时间6.73秒,绝对不能容

本文最后更新时间:  2023-03-08 18:54:18

渴望登顶的登山者不会被沿途的足迹所陶醉。

1前言

如下,我这里有一个问题记录表。


我需要从列表中随机选择4条数据,所以我会这样写(随机排序,取前4条)


执行时间6.73秒,绝对不能容忍。你知道这个过程中发生了什么吗???

MySQL 2的随机查询进程内存临时表

select * from question_extracting order by rand() limit 4

上面这句话先随机排序,然后取前四项。其执行过程如下:

第一步 创建一个临时表,有两个字段,一个是double 类型使用A表示,另一个是 varchar(64) 类型 使用B表示,记为 字段 W,需要注意的是这个表没有建索引。第二步就是 从 上述 question_extracting 表中,按主键顺序取出所有的行(因为这里需要的是每行的所有数据),对于每一行数据,调用 rand() 函数生成一个大于 0 小于 1 的随机小数,并把这个随机小数和这一行数据 分别存入临时表的 A 和 B 字段中,需要扫描全表,如这里的 4974098 行。第三步就是在临时表中按照字段 A 排序,初始化 sort_buffer,sort_buffer 中会放两个字段,一个是 double 类型,用来放临时表中的 A 字段,另一个是整型,用来放临时表中对应的数据的行号。第四步就是在 sort_buffer 中根据 A 的值进行排序,排序完成后,取出前 4 个结果的位置信息,然后回到依次到内存临时表中取出 对就的行信息 值,返回给 客户端。

在上面的过程中,第二步扫描了整个question_extracting表的4974098行,第三步也扫描了临时表的4974098行,然后最后一步扫描了4行数据得到数据,所以这个查询总共扫描了4974098 +4974098+4次。

在上面的过程中,order by rand()使用了临时内存表,在对临时内存表进行排序时使用了rowid排序方法。这个临时表没有主键ID,临时生成的长度为6字节的rowid作为主键。

MySQL 3的rand查询进程盘临时表

在MySql中,参数tmp_table_size限制了临时内存表的大小,默认值为16M。如果临时表的大小超过了tmp_table_size,那么临时内存表将被转换为临时磁盘表。

当使用临时磁盘表时,可以在没有显式索引的情况下对InnoDB表进行排序。

在这个过程中,使用了MySQL版引入的优先级队列排序算法。例如,我们随机选择上面提到的值。根据优先级队列排序算法,我们只需要取出临时表中最小的四个A值对应的数据。这个过程可以简要描述如下:

第一步 对于临时表中这 4974098 个准备排序的 (A,rowid),先取前四行,构造成一个堆(可以理解为一个组)第二步 取下一个行 (R’,rowid’),跟当前堆里面最大的 R 比较,如果 R’小于 R,把这个 (R,rowid) 从堆中去掉,换成 (R’,rowid’)重复第 2 步,直到第 4974098 个 (R’,rowid’) 完成比较最后一步就是 拿到这最小的4个值后,回到临时表中取出对应的数据。

3 MySQL随机排序的正确姿势

随机取一段数据,在开头写下如下内容:

随机算法的正确姿态


你没看错,这是正确的写法。

select max(id),min(id) into @A,@B from question_extracting ;set @C= floor((@A-@B+1)*rand() + @B);select * from question_extracting where id >= @C limit 1;

可以描述如下:

第一步 取得这个表的主键 id 的最大值 M 和最小值 N,这个过程不需要扫描表第二步 用随机函数生成一个最大值到最小值之间的数 C = (A-B)*rand() + B;第三步 取不小于 C 的第一个 ID 的行


结束

不局限于思维和语言的限制才是编程的最高境界。

推荐:MySql。真的可以用字符串索引吗?

温馨提示:内容均由网友自行发布提供,仅用于学习交流,如有版权问题,请联系我们。