【MySQL】查询优化实例解析-延迟关联优化
【提出问题】
CREATE TABLE `t` ( `a0` ) NOT NULL, `a1` ) NOT NULL, `a2` ,) NOT NULL DEFAULT '0.000000000', `a3` ,) NOT NULL DEFAULT '0.000000000', `a4` ,) NOT NULL DEFAULT '0.000000000', `a5` ,) NOT NULL DEFAULT '0.000000000', `a6` ,) NOT NULL DEFAULT '0.000000000', `a7` ,) NOT NULL DEFAULT '0.000000000', `a8` ,) NOT NULL DEFAULT '0.000000000', `a9` ,) NOT NULL DEFAULT '0.000000000', `b1` ,) NOT NULL DEFAULT '0.000000000', `b2` ,) NOT NULL DEFAULT '0.000000000', `b3` ,) NOT NULL DEFAULT '0.000000000', `b4` ,) NOT NULL DEFAULT '0.000000000', `b5` ,) NOT NULL DEFAULT '0.000000000', `b6` ,) NOT NULL DEFAULT '0.000000000', `b7` ,) NOT NULL DEFAULT '0.000000000', `b8` ,) NOT NULL DEFAULT '0.000000000', `b9` ,) NOT NULL DEFAULT '0.000000000', `c1` ,) NOT NULL DEFAULT '0.000000000', `c2` ,) NOT NULL DEFAULT '0.000000000', `c3` ,) NOT NULL DEFAULT '0.000000000', `c4` ,) NOT NULL DEFAULT '0.000000000', `c5` ,) NOT NULL DEFAULT '0.000000000', `c6` ,) NOT NULL DEFAULT '0.000000000', `c7` ) ', `c8` ) ', `c9` ) ', `d1` ) ', `d2` ) ', `d3` ,) NOT NULL DEFAULT '0.000000000', `d4` ,) NOT NULL DEFAULT '0.000000000', `d5` ,) NOT NULL DEFAULT '0.000000000', `d6` ,) NOT NULL DEFAULT '0.000000000', `d7` ,) NOT NULL DEFAULT '0.000000000', `d8` ,) NOT NULL DEFAULT '0.000000000', `d9` ) ', `e1` ,) NOT NULL DEFAULT '0.000000000', `e2` ,) NOT NULL DEFAULT '0.000000000', `e3` ,) NOT NULL DEFAULT '0.000000000', `e4` ,) NOT NULL DEFAULT '0.000000000', `e5` ,) NOT NULL DEFAULT '0.000000000', `e6` ,) NOT NULL DEFAULT '0.000000000', `e7` ,) NOT NULL DEFAULT '0.000000000', `e8` ,) NOT NULL DEFAULT '0.000000000', `e9` ,) NOT NULL DEFAULT '0.000000000', `f1` ,) NOT NULL DEFAULT '0.000000000', `f2` ,) NOT NULL DEFAULT '0.000000000', PRIMARY KEY (`a0`,`a1`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
表基本信息
SELECT * FROM tables where table_name='t'\G
. row ***************************
TABLE_CATALOG: def
TABLE_SCHEMA: test
TABLE_NAME: t
TABLE_TYPE: BASE TABLE
ENGINE: InnoDB
VERSION:
ROW_FORMAT: Compact
TABLE_ROWS:
AVG_ROW_LENGTH:
DATA_LENGTH:
MAX_DATA_LENGTH:
INDEX_LENGTH:
DATA_FREE:
AUTO_INCREMENT: NULL
CREATE_TIME: ::
UPDATE_TIME: NULL
CHECK_TIME: NULL
TABLE_COLLATION: utf8_general_ci
CHECKSUM: NULL
CREATE_OPTIONS:
TABLE_COMMENT:
原始SQL
--SQL1-- ,; row in SET (6.67 sec) --SQL2-- ,) AS A USING (a0, a1); row in set (0.90 sec)
- 使用 Optimizer Trace 观察SQL执行过程(http://www.cnblogs.com/skylerjiang/p/mysql_optimizer_trace_intro.html)
- MySQL排序内部原理探秘 (http://geek.csdn.net/news/detail/105891)
SHOW variables like '%sort%';
+--------------------------------+---------------------+
| Variable_name | Value |
+--------------------------------+---------------------+
|
|
+--------------------------------+---------------------+
排序buffer为8M
SET optimizer_trace="enabled=on";
;
SELECT trace FROM information_schema.optimizer_trace\G
【问题分析】
SQL1执行过程
,; SELECT trace FROM information_schema.optimizer_trace\G

- SELECT *, 读取数据的时候,需要读取所有的字段。
- a1没有索引,将使用全表扫描。
- priority_queue优化检查
- LIMIT 100000,1 需要排序TOP 100001行(再丢弃100000行,取1行)
- 每行454字节,100001行需要45,400,454字节,大于sort_buffer_size(8,388,608),数据集无法直接纳入buffer
- 尝试去除additionl_fields(数据字段),使用sortkey+rowid的方式,row_size=74,可以在buffer中存放
- 估算merge_sort和priority_queue_cost,前者比后者小,放弃使用priority_queue
- sort_mode=<sort_key,additional_fields>,需要使用外部排序,分片数量46。
SQL2执行过程
,) AS A USING (a0, a1); SELECT trace FROM information_schema.optimizer_trace\G

- 首先执行子查询 SELECT a0, a1 FROM t ORDER BY a1 DESC LIMIT 100000,1
- 只需要读取a0和a1两个字段
- a1没有索引,将使用全表扫描。
- priority_queue优化检查
- LIMIT 100000,1 需要排序TOP 100001行(丢弃100000行,取1行)
- 每行66字节,100001行需要6,600,066字节,小于sort_buffer_size(8,388,608),数据集可以纳入buffer
- 使用priority_queue
- 执行完毕,结果存储在临时表A里面
- 临时表A只有1行,连表查询时,可以使用 t 的主键,非常快速。
结论
- 全表扫描时,SQL1需要读取所有字段(大约500字节),SQL2只需要读取2个字段(小于100字节)。
- SQL1需要使用外部排序,分片数量又比较多(46个),所以比较慢。
- SQL2数据可以存放在sort_buffer里面,还可以启用优先队列优化,加速明显。
【场景扩展】
1. Limit对执行过程的影响
SQL1执行过程
,; row in set (8.82 sec) SELECT trace FROM information_schema.optimizer_trace\G

这次的执行过程完全一样,但决策依据稍有不同。600001行数据,即使去除additional fields,也需要44,400,074字节,超过了8M的sort_buffer_size,not_enough_space,无法使用priority_queue。原来是因为priority_queue_cost>merge_sort_cost而放弃。
SQL2执行过程
,) AS A USING (a0, a1); row in set (1.05 sec) SELECT trace FROM information_schema.optimizer_trace\G

- 无法启用优先队列优化,
使用了外部排序,共8个分片。
2. 不同sort_mode的影响
;
SQL1执行过程
,; row in set (4.16 sec)

排序模式变成了rowid模式,速度变快了。这是因为排序时只需要读取排序字段和rowid,外部排序的分片数量减少了。
SQL2执行过程
,) AS A USING (a0, a1); row in set (1.05 sec)
执行模式没有改变,因为sizeof(a0+a1)<100,还是能用priority_queue优化。
【参考资料】
- 使用 Optimizer Trace 观察SQL执行过程(http://www.cnblogs.com/skylerjiang/p/mysql_optimizer_trace_intro.html)
- MySQL排序内部原理探秘 (http://geek.csdn.net/news/detail/105891)
- filesort.cc 源代码阅读笔记 http://www.cnblogs.com/skylerjiang/p/6269310.html
【MySQL】查询优化实例解析-延迟关联优化的更多相关文章
- MySQL 分页查询优化——延迟关联优化
目录 1. InnoDB表的索引的几个概念 2. 覆盖索引和回表 3. 分页查询 4. 延迟关联优化 写在前面 下面的介绍均是在选用MySQL数据库和Innodb引擎的基础开展.我们先 ...
- mysql 利用延迟关联优化查询(select * from your_table order by id desc limit 2000000,20)
其实在我们的工作中类似,select * from your_table order by id desc limit 2000000,20会经常遇见,比如在分页中就很常见. 如果我们的sql中出现这 ...
- Mysql覆盖索引与延迟关联
延迟关联:通过使用覆盖索引查询返回需要的主键,再根据主键关联原表获得需要的数据. 为什innodb的索引叶子节点存的是主键,而不是像myisam一样存数据的物理地址指针? 如果存的是物理地址指针不 ...
- Mysql查询优化器之关于JOIN的优化
连接查询应该是比较常用的查询方式,连接查询大致分为:内连接.外连接(左连接和右连接).自然连接 下图展示了 LEFT JOIN.RIGHT JOIN.INNER JOIN.OUTER JOIN 相关的 ...
- PHP使用Mysql事务实例解析
<?php //数据库连接 $conn = mysql_connect('localhost', 'root', ''); mysql_select_db('test', $conn); mys ...
- mysql通过“延迟关联”进行limit分页查询优化的一个实例
最近在生产上遇见一个分页查询特别慢的问题,数据量大概有200万的样子,翻到最后一页性能很低,差不多得有4秒的样子才能出来整个页面,需要进行查询优化. 第一步,找到执行慢的sql,如下: SELECT ...
- 【MySQL】性能优化 之 延迟关联
[背景] 某业务数据库load 报警异常,cpu usr 达到30-40 ,居高不下.使用工具查看数据库正在执行的sql ,排在前面的大部分是: SELECT id, cu_id, name, in ...
- MySQL性能优化之延迟关联
[背景] 某业务数据库load 报警异常,cpu usr 达到30-40 ,居高不下.使用工具查看数据库正在执行的sql ,排在前面的大部分是: SELECT id, cu_id, name, in ...
- mysql优化----大数据下的分页,延迟关联,索引与排序的关系,重复索引与冗余索引,索引碎片与维护
理想的索引,高效的索引建立考虑: :查询频繁度(哪几个字段经常查询就加上索引) :区分度要高 :索引长度要小 : 索引尽量能覆盖常用查询字段(如果把所有的列都加上索引,那么索引就会变得很大) : 索引 ...
随机推荐
- jquery uploadifive使用
应为考虑到flash将逐渐被淘汰,所以选择了uploadfive完成上传 js文件和css文件自行下载,我上传了免费版(啃爹的官网竟然收费) 文件引入之后: <input type=" ...
- [APUE]进程控制(中)
一.wait和waitpid函数 当一个进程正常或异常终止时会向父进程发送SIGCHLD信号.对于这种信号系统默认会忽略.调用wait/waidpid的进程可能会: 阻塞(如果其子进程都还在运行); ...
- Dubbo源码学习--注册中心分析
相关文章: Dubbo源码学习--服务是如何发布的 Dubbo源码学习--服务是如何引用的 注册中心 关于注册中心,Dubbo提供了多个实现方式,有比较成熟的使用zookeeper 和 redis 的 ...
- 快速上手微信小程序-快递100
2007 年 1 月 9 日,乔布斯在旧金山莫斯科尼会展中心发布了首款 iPhone,而在十年后的 1 月 9 日,微信小程序正式上线.张小龙以这样的形式,向乔布斯致敬. 小程序在哪里? 小程序功能模 ...
- SASS使用CSS3动画并使动画暂停和停止在最后一帧的简单例子
今天在手机上试了试这个 css3 动画效果,可以把动画效果停留在最后一帧上,以及鼠标 :hover 暂停动画,比较实用的功能,不用 JS 也能实现这些效果了. 不过测试体验感觉手机上没有 jQuery ...
- [留念贴] C#开发技术期末大作业——星月之痕
明天就要去上海大学参加 2015赛季 ACM/ICPC最后一场比赛 —— EC-Final,在这之前,顺利地把期末大作业赶出来了. 在这种期末大作业10个人里面有9个是从网上下载的国内计算机水平五六流 ...
- ToDictionary用法
ToDictionary其实可以简单化,可以传两个lambada表达式,第一个是Key,第二个就是Value. ToDictionary( key => key.Attribute(" ...
- SpringMVC实现注解式权限验证(转)
SpringMVC学习系列(9) 之 实现注解式权限验证 对大部分系统来说都需要权限管理来决定不同用户可以看到哪些内容,那么如何在Spring MVC中实现权限验证呢?当然我们可以继续使用serv ...
- Amabri添加YDB报错
点部署直接出现如下图: 通过查看日志: tail -f /var/log/ambari-server/ambari-server.log java.lang.RuntimeException: Una ...
- [MFC美化] SkinMagic使用详解1- SkinMagic使用流程
[SkinMagic使用流程] 1.工程配置SkinMagic相关文件 2.初始化SkinMagic皮肤文件,窗体加载皮肤 3.释放皮肤资源 特别声明,SkinMagic要是破解版的,如果不是,可能需 ...