全字段排序和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. weixueyuan-Nginx微服务11

    https://www.weixueyuan.net/nginx/microservices/ 微服务是什么 计算机自诞生以来,极大地影响了人类的生产和社会活动,软件生产以一种生产活动的方式进入了人们 ...

  2. 【Netty】(5)-源码 Bootstrap

    [Netty]5 源码 Bootstrap 上一篇讲了AbstractBootstrap,为这篇做了个铺垫. 一.概述 Bootstrap 是 Netty 提供的一个便利的工厂类, 我们可以通过它来完 ...

  3. STL 容器操作

    vector set转化为vector:vec.assign(set.begin(), set.end()) map 1. map默认从小到达排序,想要从大到小,可以: map<string, ...

  4. Sybaris pg walkthrough Intermediate 从redis 到 rce

    nmap ┌──(root㉿kali)-[~/lab] └─# nmap -p- -A 192.168.166.93 Starting Nmap 7.94SVN ( https://nmap.org ...

  5. 3 x 2 + 1 !安 全 能 力 权 威 认 可 !

    近日,由XOps大会组委会主办的"2024第三届XOps产业创新发展论坛"在北京召开.大会主论坛公布了2024上半年XOps最新评估结果,天翼云顺利通过ITU DevOps国际标准 ...

  6. ABB机器人本体维修保养方法

    ABB机器人维修保养一般可以参照机器人保养手册里面的描述,这种保养一般分为两种计时方式,一两年内进行一次基础保养或者机器人运行时间不超过10000小时.在对机器人本体进行保养的时候,我们该如何操作呢? ...

  7. 泰山派(Ubuntu 20.0)更换软件源

    泰山派更换软件源 1.编辑apt软件包源获取文件 vim /etc/apt/sources.list 2.更换为下面的源 deb http://mirrors.ustc.edu.cn/ubuntu-p ...

  8. JavaScript 之 高级程序设计 基础篇 (一)

    导读 此篇文章为作者拜读JavaScrpit 第四版(红宝石)的笔记内容.适用于有经验的程序员阅读:作者 java开发出身.在之前前后端不分离的时代 使用esayUI JQuery的时代 经常写 js ...

  9. MySQL - [18] mysql中关于cascade的用法

    drop database语句用于删除数据库.但如果想要删除一个数据库并且还要删除所有依赖于该数据库的存储过程.函数等,可以使用cascade关键字.drop database test cascad ...

  10. Kubernetes - [04] 常用命令

    kubectl 语法 kubectl [command] [TYPE] [NAME] [flags] command:指定在一个或多个资源商要执行的操作.例如:create.get.describe. ...