有一张财务流水表,未分库分表,目前的数据量为9555695,分页查询使用到了limit,优化之前的查询耗时16 s 938 ms (execution: 16 s 831 ms, fetching: 107 ms),按照下文的方式调整SQL后,耗时347 ms (execution: 163 ms, fetching: 184 ms);

操作: 查询条件放到子查询中,子查询只查主键ID,然后使用子查询中确定的主键关联查询其他的属性字段;

原理: 减少回表操作;

一:前言

首先说明一下MySQL的版本:

表结构:

id为自增主键,val为非唯一索引。

灌入大量数据,共500万:

我们知道,当limit offset rows中的offset很大时,会出现效率问题:

为了达到相同的目的,我们一般会改写成如下语句:

时间相差很明显。

为什么会出现上面的结果?我们看一下select * from test where val=4 limit 300000,5;的查询过程:

  • 查询到索引叶子节点数据。
  • 根据叶子节点上的主键值去聚簇索引上查询需要的全部字段值。

类似于下面这张图:

像上面这样,需要查询300005次索引节点,查询300005次聚簇索引的数据,最后再将结果过滤掉前300000条,取出最后5条。MySQL耗费了大量随机I/O在查询聚簇索引的数据上,而有300000次随机I/O查询到的数据是不会出现在结果集当中的。

肯定会有人问:既然一开始是利用索引的,为什么不先沿着索引叶子节点查询到最后需要的5个节点,然后再去聚簇索引中查询实际数据。这样只需要5次随机I/O,类似于下面图片的过程

其实我也想问这个问题。

二:证实

下面我们实际操作一下来证实上述的推论:

为了证实select * from test where val=4 limit 300000,5是扫描300005个索引节点和300005个聚簇索引上的数据节点,我们需要知道MySQL有没有办法统计在一个sql中通过索引节点查询数据节点的次数。我先试了Handler_read_*系列,很遗憾没有一个变量能满足条件。

我只能通过间接的方式来证实:

InnoDB中有buffer pool。里面存有最近访问过的数据页,包括数据页和索引页。所以我们需要运行两个sql,来比较buffer pool中的数据页的数量。预测结果是运行select * from test a inner join (select id from test where val=4 limit 300000,5); 之后,buffer pool中的数据页的数量远远少于select * from test where val=4 limit 300000,5;对应的数量,因为前一个sql只访问5次数据页,而后一个sql访问300005次数据页。

select * from test where val=4 limit 300000,5

 mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;Empty set (0.04 sec)

可以看出,目前buffer pool中没有关于test表的数据页。

可以看出,此时buffer pool中关于test表有4098个数据页,208个索引页。

select * from test a inner join (select id from test where val=4 limit 300000,5) ;为了防止上次试验的影响,我们需要清空buffer pool,重启mysql。

mysqladmin shutdown/usr/local/bin/mysqld_safe &
mysql> select index_name,count(*) from information_schema.INNODB_BUFFER_PAGE where INDEX_NAME in('val','primary') and TABLE_NAME like '%test%' group by index_name;Empty set (0.03 sec)

运行sql:

我们可以看明显的看出两者的差别:第一个sql加载了4098个数据页到buffer pool,而第二个sql只加载了5个数据页到buffer pool。符合我们的预测。也证实了为什么第一个sql会慢:读取大量的无用数据行(300000),最后却抛弃掉。而且这会造成一个问题:加载了很多热点不是很高的数据页到buffer pool,会造成buffer pool的污染,占用buffer pool的空间。遇到的问题

为了在每次重启时确保清空buffer pool,我们需要关闭innodb_buffer_pool_dump_at_shutdown和innodb_buffer_pool_load_at_startup,这两个选项能够控制数据库关闭时dump出buffer pool中的数据和在数据库开启时载入在磁盘上备份buffer pool的数据。

一次SQL查询优化原理分析(900W+数据,从17s到300ms)的更多相关文章

  1. 一次SQL查询优化原理分析(900W+数据,从17s到300ms) (转)

    有一张财务流水表,未分库分表,目前的数据量为9555695,分页查询使用到了limit,优化之前的查询耗时16 s 938 ms (execution: 16 s 831 ms, fetching: ...

  2. PDO防sql注入原理分析

    使用pdo的预处理方式可以避免sql注入. 在php手册中'PDO--预处理语句与存储过程'下的说明: 很多更成熟的数据库都支持预处理语句的概念.什么是预处理语句?可以把它看作是想要运行的 SQL 的 ...

  3. 手动SQL注入原理分析与实践

    代码仓库 本文所用代码的代码库地址: 点击这里前往Github仓库 了解SQL注入 定义 SQL注入攻击(SQL Injection),简称注入攻击,是Web开发中最常见的一种安全漏洞.可以用它来从数 ...

  4. MyBatis动态SQL底层原理分析 与 JavaScript中的Date对象,以及UTC、GMT、时区的关系

    http://fangjian0423.github.io/categories/mybatis/ http://xtutu.me/the-date-object-in-js/

  5. 基于简单sql语句的sql解析原理及在大数据中的应用

    基于简单sql语句的sql解析原理及在大数据中的应用 李万鸿 老百姓呼吁打土豪分田地.共同富裕,总有一天会实现. 全面了解你所不知道的外星人和宇宙真想:http://pan.baidu.com/s/1 ...

  6. Android应用程序组件Content Provider在应用程序之间共享数据的原理分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6967204 在Android系统中,不同的应用 ...

  7. SQL注入原理及代码分析(一)

    前言 我们都知道,学安全,懂SQL注入是重中之重,因为即使是现在SQL注入漏洞依然存在,只是相对于之前现在挖SQL注入变的困难了.而且知识点比较多,所以在这里总结一下.通过构造有缺陷的代码,来理解常见 ...

  8. SQL注入原理及代码分析(二)

    前言 上一篇文章中,对union注入.报错注入.布尔盲注等进行了分析,接下来这篇文章,会对堆叠注入.宽字节注入.cookie注入等进行分析.第一篇文章地址:SQL注入原理及代码分析(一) 如果想要了解 ...

  9. flink-----实时项目---day07-----1.Flink的checkpoint原理分析 2. 自定义两阶段提交sink(MySQL) 3 将数据写入Hbase(使用幂等性结合at least Once实现精确一次性语义) 4 ProtoBuf

    1.Flink中exactly once实现原理分析 生产者从kafka拉取数据以及消费者往kafka写数据都需要保证exactly once.目前flink中支持exactly once的sourc ...

随机推荐

  1. windows下使用dos命令手工与ntp服务器同步系统时间

    管理员模式的命令窗口 net stop w32time &w32tm /unregister &w32tm /register &net start w32time & ...

  2. 【Docker】7. 镜像-加载原理、分层原理、commit镜像

    一.什么是镜像 镜像是一种轻量级.可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件. 它包含运行某个软件所需的所有内容,包括代码.运行时环境.库.环境变量和配置文件. 所有的应用,直接 ...

  3. CRM帮助初创企业降本增效的四个方法

    对大部分初创公司来说,只有少数企业能够实现盈利,大部分只能维持盈亏平衡甚至是亏损.这是因为初创企业很难在短时间之内找到稳定的赢利点,而企业面临的风险和投入又是无法预知的.初创企业想要快速盈利,只能降低 ...

  4. Spring Cloud Alibaba Nacos Discovery 实战

    Nacos 作为服务注册中心,可以快速简单的将服务自动注册到 Nacos 服务端,并且能够动态无感知的刷新某个服务实例的服务列表,为分布式系统提供服务注册与发现功能 一.创建服务 1.创建项目 pom ...

  5. win10系统U盘读取不了怎么解决 三种方法快速解决"文件或目录损坏且无法读取& 发布时间:2020-06-05 09:19:46 作者:佚名 我要评论

    win10系统U盘读取不了怎么解决 三种方法快速解决"文件或目录损坏且无法读取&   发布时间:2020-06-05 09:19:46   作者:佚名    我要评论 win10电脑 ...

  6. Select Screen 0 with xrandr Ask QuestionScreen 0" here describes your whole virtual display made of these two outputs: eDP-1-

    Screen 0" here describes your whole virtual display made of these two outputs: eDP-1-1: physica ...

  7. python文件对象几种操作模式区别——文件操作方法详解

    文件对象的字节模式/b模式(以utf-8编码为例) 读操作 写操作 指针操作 ASCII字节 返回bytes/字节类型的Ascii 写入bytes类型字节 例如:b'This is ascii' 使用 ...

  8. touch -d 同时修改atime与mtime

    1.touch命令 touch命令用于创建空白文件或设置文件的时间,格式为"touch [选项] [文件]". 在创建空白的文本文件方面,这个touch命令相当简捷,简捷到没有必要 ...

  9. Linux 根目录所在分区被脏数据占满

    背景: ​ 公司在做一个项目,大概功能就是一个通行闸机的人脸识别系统,要经过门禁的人注册了之后,系统就会存储一张原始的图片在服务器的数据文件夹里面,包括了永久的存储和一些访客注册临时存储.一天周五的时 ...

  10. scala :: , +:, :+ , ::: , ++ 的区别

    4 种操作符的区别和联系 :: 该方法被称为cons,意为构造,向队列的头部追加数据,创造新的列表.用法为 x::list,其中x为加入到头部的元素,无论x是列表与否,它都只将成为新生成列表的第一个元 ...