栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

MySQL对临时表排序——随机展示数据示例

author:陈镇坤27

创建时间:2021年11月21日18:53:26

转载请注明出处

文章目录
  • MySQL对临时表排序——随机展示数据示例
      • 问:临时表分哪几种?
      • 问:为什么会使用临时表?
    • 内存临时表
      • 问:举一个例子,并说明排序过程中临时表的作用。
      • 问:当使用到临时表的rowid排序时,为什么sort_buffer中初始化的字段之一id被替换为位置信息了?
      • 问:为什么隐式自增索引的rowid是6字节?
      • 问:sort_buffer的排序涉及到什么排序算法?
    • 磁盘临时表
      • 问:复现一个使用临时表的排序语句场景。
      • 问:有一个场景,明明需要进行排序的数据总量超过sort_buffer_size,但是查看优化日志发现,该排序并没有借助外部磁盘文件,可能的原因是什么?解释一下。
      • 问:什么是堆排序?
      • 问:全字段排序和rowid排序对应的最佳场景是什么?
    • 随机排序
      • 问:要实现随机查询的功能,使用order by rand()可以吗?不可以的话使用什么方式好一些?
      • 问:随机查询的话,可以用下面的例子吗,不可以的话解释下原因。
      • mysql> select max(id),min(id) into @M,@N from t ;

——————————————————————————————

问:临时表分哪几种?

答:内存临时表和磁盘临时表,磁盘临时表又可以根据引擎区分为Innodb类型或MyINSAM类型。

问:为什么会使用临时表?

答:(个人理解)当执行语句需要对获取得到的数据进行额外的整理,并且这种处理是在表层面上进行时。例如需要对每一行获取的值,进行随机赋值,得到的值需要进行存储。

需要注意的是,使用派生表的情景没有必要在extra中特意说明使用了临时表(EXPLAIN does not necessarily say Using temporary for derived or materialized temporary tables.)

具体的触发关键字或场景在官方文档中地址位置:https://dev.mysql.com/doc/refman/8.0/en/internal-temporary-tables.html

PS:临时表会在本线程执行完结束后释放。

内存临时表 问:举一个例子,并说明排序过程中临时表的作用。

答:假设表数据有10000行,一个id主键字段和word字符字段。

select  word  from t order by rand() limit 3

执行结果中,extra为:Using temporary、Using filesort

执行流程:

1、创建引擎为memory(无索引)的临时表,表字段有R(随机数)和W(word);

2、扫描t表,每一行都单独进行rand()函数运算,将求值与字段word逐行存入临时表,直到符合筛选条件数据全部存完。

3、初始化sort_buffer,有字段R(随机值为double类型)和P(P为临时表的行数据对应位置信息(整型),对应下面的rowid排序中的rowid);

4、将临时表中的行数据逐行加载进sort_buffer;

5、sort_buffer对R进行排序;(此时采取的是堆排序算法)

6、根据sort_buffer前三的数据的位置信息,逐一回临时表获取对应数据,并直接返回给客户端。

PS:查询慢日志结果,可以结合上面步骤分析为什么扫描次数是20003行。

# Query_time: 0.003494  Lock_time: 0.000101 Rows_sent: 3  Rows_examined: 20003
SET timestamp=1637290944;
select word from words order by rand() limit 3;
问:当使用到临时表的rowid排序时,为什么sort_buffer中初始化的字段之一id被替换为位置信息了?

答:所谓rowid,是每个引擎用来唯一标识数据行的信息。当临时表是内存表时,相当于数组的下标便是其唯一的标识。

问:为什么隐式自增索引的rowid是6字节?

答:64位Linux操作系统下内存虚拟地址寻址空间并不是 2^64,而是 2^48 ,一个字节8bit,所以是6字节。

问:sort_buffer的排序涉及到什么排序算法?

答:

如果只获取排序数据中的一小部分,使用堆排序,此时即使数据总大小超出sort_buffer,也不需要使用到外部文件(前提是sort_buffer能容纳所谓的“数据中的一小部分”(除非你恶搞,不然当选择堆排序时,都能满足));

如果排序的数据总大小超出sort_buffer,外部文件会采用归并排序;

如果排序的数据总大小没超出sort_buffer,sort_buffer内会采取快速排序。

磁盘临时表 问:复现一个使用临时表的排序语句场景。

答:

show VARIABLES like '%tmp_table_size%';
show VARIABLES like '%sort_buffer_size%';
show VARIABLES like '%max_length_for_sort_data%';


set tmp_table_size=1024;
set sort_buffer_size=32768;
set max_length_for_sort_data=16;
SET optimizer_trace='enabled=on'; 

select word from words order by rand() limit 3;

SELECt * FROM `information_schema`.`OPTIMIZER_TRACE`G
问:有一个场景,明明需要进行排序的数据总量超过sort_buffer_size,但是查看优化日志发现,该排序并没有借助外部磁盘文件,可能的原因是什么?解释一下。

答:该排序语句仅需要返回少部分排序完毕的数据,此时在sort_buffer会使用堆排序算法。(查前三,则每次在sort_buffer中只会存在4行数据,其中一条会被替换)

问:什么是堆排序?

答:(知道怎么做,但数学原理不了解)

首先构建完全二叉树(不需要排序),根据选择构建大堆顶或小堆顶,前者是儿子比父亲小,后者反之。

从下到上,每次都只对一个最小堆进行最大(最小)的置顶,然后对同层的另一个最小堆做同样的操作,总体上逐一向顶推进,最后得到整个树最大(最小)的堆。

首先将序列按照完全二叉树方式进行排列,从底部的最小堆往上,以堆为单位,先找非叶子节点,然后以此和自己的孩子做比较,与最大值做交替,如果交替后的小值成为下面的孩子的新的父亲,则要判断是否有打破大顶堆规则,有的话,继续调整。

问:全字段排序和rowid排序对应的最佳场景是什么?

答:首先,根据是否有临时表做判断。

如果是内存临时表,证明回表查询过程不需要进行磁盘IO,此时进行rowid排序速度最快。

如果是Innodb表(包括用户创建的表和磁盘临时表),则根据配置的max_length_for_sort_data长度来进行选择,大于,则进行rowid排序,否则进行全字段排序。

随机排序 问:要实现随机查询的功能,使用order by rand()可以吗?不可以的话使用什么方式好一些?

答:不可以。因为过程性能开销大。

建议通过行的总数进行随机查。

方法如下:

取总行数–总行数取随机值–limit查询该值

select count(*) into @C from t;
set @Y = floor(@C * rand());
set @sql = concat("select * from t limit ", @Y, ",1");
prepare stmt from @sql;
execute stmt;
DEALLOCATE prepare stmt;

该查询仅需要遍历主键索引树的叶节点链表即可。

扫描行数为C+Y+1。

即使随机rand得到的值要扫描的行数=表的行数,其性能也远比order rand()要好——主键索引树天然排序。

如果要查三个随机数,则执行三次即可

select count(*) into @C from t;
set @Y1 = floor(@C * rand());
set @Y2 = floor(@C * rand());
set @Y3 = floor(@C * rand());
select * from t limit @Y1,1; //在应用代码里面取Y1、Y2、Y3值,拼出SQL后执行
select * from t limit @Y2,1;
select * from t limit @Y3,1;

而这又可继续优化:将得到的y1到y3中最大和最小的数取出,记为M和N

select * from t limit N, M-N+1;
问:随机查询的话,可以用下面的例子吗,不可以的话解释下原因。 mysql> select max(id),min(id) into @M,@N from t ;

set @X= floor((@M-@N+1)*rand() + @N);
select * from t where id >= @X limit 1;

答:不可以。id与id之间可能存在空洞,则区间段随机命中概率不等。

mysql> select max(id),min(id) into @M,@N from t ;
set @X= floor((@M-@N+1)*rand() + @N);
select * from t where id >= @X limit 1;

答:不可以。id与id之间可能存在空洞,则区间段随机命中概率不等。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/584026.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号