全字段排序和rowId排序

建表语句如下:

CREATE TABLE `t` (
`id` int(11) NOT NULL,
`city` varchar(16) NOT NULL,
`name` varchar(16) NOT NULL,
`age` int(11) NOT NULL,
`addr` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `city` (`city`)
) ENGINE=InnoDB;

sql语句如下:

select city,name,age from t where city='杭州' order by name limit 1000  ;

相关概念定义

sort_buffer:MySQL会给每个线程分配一块内存区域用于排序,这块区域叫sort_buffer。如果待排序的数据足够存放在sort_buffer中,那么就会直接用这块区域进行排序,算法为快速排序;如果待排序的数据超过了sort_buffer大小,会使用磁盘临时文件来辅助排序,算法为归并排序。

全字段排序:sort_buffer中存储的待排序数据,包括需要返回的所有字段,比如,上面sql语句中的city,name,age,虽然只用name来排序,但是还是冗余存放了city和age的数据,排序完直接返回即可。

rowId排序:sort_buffer中存储的待排序数据,只包括待排序字段和对应行的主键id,比如,上面sql语句,如果使用rowId排序,那么sort_buffer中只会存储name和rowID字段,等到排序完毕,需要回表查询出来需要返回的其他字段数据。

什么时候选择全字段排序?什么时候选择rowID排序?

当MySQL判断,当待处理表为InnoDB磁盘表时,会优先使用全字段排序,目的是为了减少rowID排序最后需要再次回表查询需要返回的字段的操作开销,但是全字段排序如果需要冗余的单行数据量太大时,就不会选择全字段排序,而选择rowID排序。

  • 如何判断单行数据是否过大?MySQL中会使用max_length_for_sort_data来判断。

为什么单行数据量大,就需要切换算法?

如果单行数据量太大,内存中能存储下的行数就会变少,就需要使用更多的磁盘临时文件来存储,排序的性能会比较差。


内存临时表和磁盘临时表

看这个业务:

有一张单词表,我们需要随机显示三个单词给用户。

建表语句和生成数据存储过程:

mysql> 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();

SQL语句:

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

注:rand() 这个函数会返回一个0~1之间的随机小数值。

当需要使用这个随机值来排序时,就需要使用临时表来存储这个随机数据。

内存临时表

执行过程如下:

  1. 首先生成Memory引擎的内存临时表,在主键索引中,依次取出所有的word值,调用rand函数生成 一个随机值,把word和随机值存储到临时表中。
  2. 然后针对这个临时表开始排序。使用sort_buffer并且使用rowId算法。
    1. 这里为什么使用rowID算法了呢?因为上面提到过的全字段排序会被优先选择,前提是待排序的表是磁盘表;现在的待排序表为Memory引擎的内存表,虽然使用rowID,但是最后的回表查询都是在内存中完成的,开销大大降低,MySQL当然会选择可以一次排序更多行的rowId算法。

磁盘临时表

MySQL中有一个参数,tmp_table_size 这个参数限制了内存临时表的大小,默认值是 16M。如果临时表大于16M,就会使用磁盘临时表来存储临时数据,默认是InnoDB引擎表。关于默认的InnoDB引擎表的排序过程,在上面的全字段排序和rowId排序中已经介绍过了。


新的排序算法

上面介绍过,InnoDB磁盘表,要么使用基于全内存的快排,要么基于辅助的磁盘临时文件的归并排序,其实在MySQL5.6之后,还引入了一种新的排序算法,优先队列排序算法。

为什么需要这种算法?

考虑刚才的SQL语句

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

无论是使用快排还是归并排序,他们都是基于所有的数据进行排序。

但分析上面的sql语句,其实我们只需要排序后的前面三条数据,并且后面的排序数据在计算上来说是浪费资源的。有没有一种算法,可以通过排序,只得到我们需要的最小的三条或者最大的三条数据,并且尽量不使用磁盘临时文件呢?

优先队列排序算法

优先队列排序算法,如果执行上面的sql语句,会先从表中顺序取最开始的3条数据,存储到一个最大堆中(最大堆:堆头永远是容器内数据的最大值)。然后遍历后面的所有数据,判断当前取值和堆最大值比较,如果比堆最大值小,就把新数据入堆,并且重新排序堆中的顺序,保持堆头为最大值。

经过这种排序以后,堆中就是我们需要的前三个最小值了。

示意图如下:

什么时候会选择这种算法?

当存在limit字句时,并且limit需要的维护的最大堆的大小小于 sort_buffer,就会使用这个算法。

MySQL-排序相关原理分析的更多相关文章

  1. PHP+MySql字符问题原理分析

    假如数据库已经设置了utf-8 ,php文件也设置了utf-8 ,但在php文件的查询语句中未添加了 mysql_query("set names utf8")语句,此时php页面 ...

  2. MySQL索引结构原理分析

    我们在学习MySQL的时候经常会听到索引这个词,大概也知道这是什么,但是深究下去又说不出什么道道来.下面将会比较全面的介绍一下关于索引! 1 索引是什么? 这里用百度百科的一句话来说,在关系数据库中, ...

  3. 干货 MySQL常见的面试题 + 索引原理分析

    常见的面试必备之MySQL索引底层原理分析: MySQL索引的本质 MySQL索引的底层原理 MySQL索引的实战经验 面试 1)问题:数据库中最常见的慢查询优化方式是什么? 回答:加索引 2)问题: ...

  4. MySQL排序原理与案例分析

    前言      排序是数据库中的一个基本功能,MySQL也不例外.用户通过Order by语句即能达到将指定的结果集排序的目的,其实不仅仅是Order by语句,Group by语句,Distinct ...

  5. MySQL排序原理与MySQL5.6案例分析【转】

    本文来自:http://www.cnblogs.com/cchust/p/5304594.html,其中对于自己觉得是重点的加了标记,方便自己查阅.更多详细的说明可以看沃趣科技的文章说明. 前言    ...

  6. [转]MySQL排序原理与案例分析

    这篇文章非常好,就把他转过来 前言      排序是数据库中的一个基本功能,MySQL也不例外.用户通过Order by语句即能达到将指定的结果集排序的目的,其实不仅仅是Order by语句,Grou ...

  7. (转)MySQL排序原理与案例分析

    前言      排序是数据库中的一个基本功能,MySQL也不例外.用户通过Order by语句即能达到将指定的结果集排序的目的,其实不仅仅是Order by语句,Group by语句,Distinct ...

  8. 重新学习Mysql数据库4:Mysql索引实现原理和相关数据结构算法

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  9. MYSQL索引结构原理、性能分析与优化

    [转]MYSQL索引结构原理.性能分析与优化 第一部分:基础知识 索引 官方介绍索引是帮助MySQL高效获取数据的数据结构.笔者理解索引相当于一本书的目录,通过目录就知道要的资料在哪里, 不用一页一页 ...

  10. 【转】由浅入深探究mysql索引结构原理、性能分析与优化

    摘要: 第一部分:基础知识 第二部分:MYISAM和INNODB索引结构 1.简单介绍B-tree B+ tree树 2.MyisAM索引结构 3.Annode索引结构 4.MyisAM索引与Inno ...

随机推荐

  1. JedisPool和Jedis推荐的生命周期

    在开发 Web 项目时,使用 Jedis 客户端与 Redis 进行交互时,通常建议将 JedisPool 设置为单例或静态的,而 Jedis 实例则不应该是单例的.以下是详细的解释和最佳实践: 1. ...

  2. 十四款常见的Web前端开发框架

    在做web开发的时候经常会遇到一个问题,那就是,选择什么样的框架来做前端开发.下面封程中把目前常用的一些前端的框架简单的给大家介绍一下. 1. BootstrapBoostrap绝对是目前最流行用得最 ...

  3. bootwiki-Elasticsearch教程

    https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html Elasticsearch教程 Elasticse ...

  4. sax, dom, jdom技术对比

    ---- sax, dom, jdom技术的优缺点比较 SAX分析器在对XML文档进行分析时,触发一系列的事件,应用程序通过事件处理函数实现对XML文档的访问.由于事件触发本身是有时序性的,因此,SA ...

  5. 阿里云开启ssl证书过程记录 NGINX

    作者简介:大家好,我是思无邪,2024 毕业生,某厂 Go 开发工程师.. 我的网站:https://www.yishanicode.top/ ,持续更新,希望对你有帮助. 如果文章或网站知识点有错误 ...

  6. GD32F103C8T6入门——GPIO配置点亮LED

    1.硬件 GD32F103C8T6最小系统板 ST-LINK V2下载器 2.GPIO说明 每个通用I/O端口都可以通过两个32位的控制寄存器(GPIOx_CTL0/ GPIOx_CTL1)和两个32 ...

  7. Windows安装MySql时出现“Failed to find valid data directory”的错误

    1.问题描述 具体错误信息如下所示: 2021-08-13T06:18:24.942954Z 0 [System] [MY-010116] [Server] D:\Net_Program\Net_My ...

  8. Java SPI机制及实现

    一.简介 SPI 的全称为 (Service Provider Interface),是 JDK 内置的一种服务提供发现机制.主要由工具类 java.util.ServiceLoader 提供相应的支 ...

  9. dp 常见套路总结

    dp 里存的东西值域不大的时候,考虑把状态中某一维和 dp 里存的东西交换,进行 dp. 连续段 dp 时,考虑把连续段化为对每个元素考虑接上一个元素. dp 里的值可能存在某个上界,超过这个值一定不 ...

  10. P1081 [NOIP 2012 提高组] 开车旅行 题解

    传送门 前言 爆肝到半夜,中间假了一次,最终调过了两个样例,交上去过了. 题解 思路 首先进行预处理. 用一种你喜欢的数据结构维护每个城市的海拔,容易求出从每个城市出发,小 \(A\) 和小 \(B\ ...