MySQL Using temporary; Using filesort INNER JOIN优化

问题

通过「SHOW FULL PROCESSLIST」语句很容易就能查到问题SQL,如下:

SELECT post.*
FROM post
INNER JOIN post_tag ON post.id = post_tag.post_id
WHERE post.status = 1 AND post_tag.tag_id = 123
ORDER BY post.created DESC
LIMIT 100

说明:因为post和tag是多对多的关系,所以存在一个关联表post_tag。

试着用EXPLAIN查询一下SQL执行计划(篇幅所限,结果有删减):

+----------+---------+-------+-----------------------------+
| table    | key     | rows  | Extra                       |
+----------+---------+-------+-----------------------------+
| post_tag | tag_id  | 71220 | Using where; Using filesort |
| post     | PRIMARY |     1 | Using where                 |
+----------+---------+-------+-----------------------------+

下面给出优化后的SQL,唯一的变化就是把连接方式改成了「STRAIGHT_JOIN」:

SELECT post.*
FROM post
STRAIGHT_JOIN post_tag ON post.id = post_tag.post_id
WHERE post.status = 1 AND post_tag.tag_id = 123
ORDER BY post.created DESC
LIMIT 100

试着用EXPLAIN查询一下SQL执行计划(篇幅所限,结果有删减):

+----------+----------------+--------+-------------+
| table    | key            | rows   | Extra       |
+----------+----------------+--------+-------------+
| post     | status_created | 119340 | Using where |
| post_tag | post_id        |      1 | Using where |
+----------+----------------+--------+-------------+

对比优化前后两次EXPLAIN的结果来看,优化后的SQL虽然「rows」更大了,但是没有了「Using filesort」,综合来看,性能依然得到了提升。

提醒:注意两次EXPLAIN结果中各个表出现的先后顺序,稍后会解释。

解释

对第一条SQL而言,为什么MySQL优化器选择了一个耗时的执行方案?对第二条SQL而言,为什么把连接方式改成STRAIGHT_JOIN之后就提升了性能?

这一切还得从MySQL对多表连接的处理方式说起,首先MySQL优化器要确定以谁为驱动表,也就是说以哪个表为基准,在处理此类问题时,MySQL优化器采用了简单粗暴的解决方法:哪个表的结果集小,就以哪个表为驱动表,当然MySQL优化器实际的处理方式会复杂许多,具体可以参考:MySQL优化器如何选择索引和JOIN顺序

说明:在EXPLAIN结果中,第一行出现的表就是驱动表。

继续post连接post_tag的例子,MySQL优化器有如下两个选择,分别是:

  • 以post为驱动表,通过status_created索引过滤,结果集119340行
  • 以post_tag为驱动表,通过tag_id索引过滤,结果集71220行

显而易见,post_tag过滤的结果集更小,所以MySQL优化器选择它作为驱动表,可悲催的是我们还需要以post表中的created字段来排序,也就是说排序字段不在驱动表里,于是乎不可避免的出现了「Using filesort」,甚至「Using temporary」。

知道了来龙去脉,优化起来就容易了,要尽可能的保证排序字段在驱动表中,所以必须以post为驱动表,于是乎必须借助「STRAIGHT_JOIN」强制连接顺序。

实际上在某些特殊情况里,排序字段可以不在驱动表里,比如驱动表结果集只有一行记录,并且在连接其它表时,索引除了连接字段,还包含了排序字段,此时连接表后,索引中的数据本身自然就是排好序的。

既然聊到这里顺带说点题外话,大家可能会遇到类似下面的问题:原本运行良好的查询语句,过了一段时间后,可能会突然变得很糟糕。一个很大可能的原因就是数据分布情况发生了变化,从而导致MySQL优化器对驱动表的选择发生了变化,进而出现索引失效的情况,所以没事最好多查查,关注一下这些情况。

时间: 2024-08-12 17:04:41

MySQL Using temporary; Using filesort INNER JOIN优化的相关文章

我的MYSQL学习心得(十六) 优化

这一篇主要介绍MYSQL的优化,优化MYSQL数据库是DBA和开发人员的必备技能 MYSQL优化一方面是找出系统瓶颈,提高MYSQL数据库整体性能:另一方面需要合理的结构设计和参数调整,以提高 用户操作响应的速度:同时还有尽可能节省系统资源,以便系统可以提供更大负荷的服务 如果大家看过我写的两篇文章,那么学习MYSQL的索引就不会太难,因为是相通的 SQLSERVER聚集索引与非聚集索引的再次研究(上) SQLSERVER聚集索引与非聚集索引的再次研究(下) 其实MYSQL也有SQLSERVER

EXPLAIN sql优化方法(2) Using temporary ; Using filesort

优化GROUP BY语句   默认情况下,MySQL对所有GROUP BY col1,col2...的字段进行排序.这与在查询中指定ORDER BY col1,col2...类似.因此,如果显式包括一个包含相同的列的ORDER BY子句,则对MySQL的实际执行性能没有什么影响. 如果查询包括GROUP BY 但用户想要避免排序结果的消耗,则可以指定ORDER By NULL禁止排序,例如:explain select id, sum(moneys) from sales2 group by i

Mysql 查询技巧:使用JOIN优化子查询

1.数据准备 mysql> select * from student; +----+--------+----------+---------+-------------+ | id | name   | idCardNo | isCadre | nickname    | +----+--------+----------+---------+-------------+ |  1 | Tom    | 350020   |       1 | Big T       | |  2 | Ji

MySQL的索引是什么?怎么优化?

索引类似大学图书馆建书目索引,可以提高数据检索的效率,降低数据库的IO成本.MySQL在300万条记录左右性能开始逐渐下降,虽然官方文档说500~800w记录,所以大数据量建立索引是非常有必要的.MySQL提供了Explain,用于显示SQL执行的详细信息,可以进行索引的优化. 一.导致SQL执行慢的原因: 1.硬件问题.如网络速度慢,内存不足,I/O吞吐量小,磁盘空间满了等. 2.没有索引或者索引失效.(一般在互联网公司,DBA会在半夜把表锁了,重新建立一遍索引,因为当你删除某个数据的时候,索

MySQL 的索引是什么?怎么优化?

索引类似大学图书馆建书目索引,可以提高数据检索的效率,降低数据库的IO成本.MySQL在300万条记录左右性能开始逐渐下降,虽然官方文档说500~800w记录,所以大数据量建立索引是非常有必要的.MySQL提供了Explain,用于显示SQL执行的详细信息,可以进行索引的优化. 一.导致SQL执行慢的原因 1.硬件问题.如网络速度慢,内存不足,I/O吞吐量小,磁盘空间满了等. 2.没有索引或者索引失效.(一般在互联网公司,DBA会在半夜把表锁了,重新建立一遍索引,因为当你删除某个数据的时候,索引

mysql如何查看索引使用情况以及优化 - guols0612

mysql中支持hash和btree索引.innodb和myisam只支持btree索引,而memory和heap存储引擎可以支持hash和btree索引 我们可以通过下面语句查询当前索引使用情况: show status like '%Handler_read%'; +-----------------------+-------+| Variable_name | Value |+-----------------------+-------+| Handler_read_first | 0

Mysql LIMIT如何正确对其进行优化

Mysql LIMIT如何正确对其进行优化 2010-05-17 17:09 佚名 博客园 字号:T | T 我们今天主要和大家分享的是Mysql LIMIT简单介绍以及如何进行优化的相关内容的描述,以下就是正文的主要内容描述. AD:51CTO 网+首届APP创新评选大赛火热启动——超百万资源等你拿! 以下的文章主要是对Mysql LIMIT简单介绍,我们大家都知道LIMIT子句一般是用来限制SELECT语句返回的实际行数.LIMIT取1个或是2个数字参数,如果给定的是2个参数,第一个指定要返

MYSQL开发性能研究——批量插入的优化措施

一.我们遇到了什么问题 在标准SQL里面,我们通常会写下如下的SQL insert语句. INSERT INTO TBL_TEST (id) VALUES(1);   很显然,在MYSQL中,这样的方式也是可行的.但是当我们需要批量插入数据的时候,这样的语句却会出现性能问题.例如说,如果有需要插入100000条数据,那么就需要有100000条insert语句,每一句都需要提交到关系引擎那里去解析,优化,然后才能够到达存储引擎做真的插入工作. 正是由于性能的瓶颈问题,MYSQL官方文档也就提到了使

MySQL 通过semi join 优化子查询

测试环境 mysql> desc class; +------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------+-------------+------+-----+---------+-------+ | class_num | int(11) | NO | PRI | NULL | | | class_name |