前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MySQL随机函数RAND

MySQL随机函数RAND

作者头像
shysh95
发布2022-02-16 21:33:23
2.5K0
发布2022-02-16 21:33:23
举报
文章被收录于专栏:shysh95shysh95
代码语言:javascript
复制
CREATE TABLE `words` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `word` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

delimiter ;;
create procedure idata()
begin
  declare i int;
  set i=0;
  while i<10000 do
    insert into words(word) values(concat(char(97+(i div 1000)), char(97+(i % 1000 div 100)), char(97+(i % 100 div 10)), char(97+(i % 10))));
    set i=i+1;
  end while;
end;;
delimiter ;

call idata();

如何随机取3个单词

代码语言:javascript
复制
select word from words order by rand() limit 3;

-- 查看上面语句的执行情况
explain select word from words order by rand() limit 3;

Extra中Using temporary表示使用临时表,Using filesort表示需要执行排序操作。

上述默认使用的临时表是内存表,对于内存表来说,回表过程只是简单地根据数据行的位置直接访问内存得到数据,并不会导致额外的磁盘访问,因此MySQL会在排序时会优先使用rowid排序。

上述SQL语句的执行过程如下:

  1. 创建一个临时表(该表使用的是memory引擎),表里有两个字段,第一个字段是double类型(记为字段R),第二个字段是varchar(64)类型(记为字段W),临时表没有索引
  2. 从word表中,按照主键顺序取出所有的word值,对于每一个word值,调用rand函数生成一个大于0小于1的随机小数,把该随机小数和word值存入临时表的R和W字段中,至此扫描行数是10000
  3. 临时表目前有10000行数据,下面需要对这个临时表按照字段R进行排序
  4. 初始化sort_buffer,sort_buffer中有两个字段,一个是double类型,另一个是整型
  5. 从内存临时表中逐行取出R值和位置信息,分别存入sort_buffer中的两个字段,此时扫描行数又增加了10000行,变成了20000(MySQL8.0.12以后这里还是10000行,应该是对内存表做了优化,有知道的朋友可以留言告诉我)
  6. 在sort_buffer中根据R值进行排序
  7. 排序完成以后,取出前三个结果的位置信息,到内存临时表中取出word值,返回给客户端。总扫描行数变为20003(MySQL8.0以后这里是10003行)。

MySQL8.0下慢查询日志如下图,扫描行数为100003行:

临时表只能是内存表么?

答案是NO。那什么时候临时表会使用内存,什么时候又会使用磁盘呢?该选择主要依赖于tmp_table_size参数的控制,默认是16M,如果临时表的大小超过了tmp_table_size,那么内存临时表就会转换为磁盘临时表。

磁盘临时表使用的默认引擎是InnoDB,由参数default_tmp_storage_engine控制。

代码语言:javascript
复制
set tmp_table_size=1024;
set sort_buffer_size=32768;
set max_length_for_sort_data=16;
/* 打开 optimizer_trace,只对本线程有效 */
SET optimizer_trace='enabled=on'; 
/* 执行语句 */
select word from words order by rand() limit 3;

/* 查看 OPTIMIZER_TRACE 输出 */
SELECT * FROM `information_schema`.`OPTIMIZER_TRACE`\G

在我们上图的输出中,我们可以看出排序算法使用了优先队列排序算法,然后是全字段排序(也就是说不用回表)。

peak_memory_used代表排序时使用到的内存,按道理应该等于sort_buffer_size指定的值,之所以不等的原因是作者本人的MySQL是8.0.12版本。

MySQL8.0.12之前,MySQL优化器会为排序直接分配sort_buffer_size指定大小的内存,但从MySQL8.0.12开始,为排序分配内存是以增量的方式进行

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-02-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员修炼笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档