【MySQL】MySQL/MariaDB的优化器对in子查询的处理

参考:http://codingstandards.iteye.com/blog/1344833

上面参考文章中《高性能MySQL》第四章第四节在第三版中我对应章节是第六章第五节

最近分析生产环境慢查询,发现上线很久但是效率不高的查询

MySQL版本5.5.18

SELECT
        loc.cell_no             AS m_cellNo
        ...
        FROM bs_loc loc LEFT JOIN st_stock_m m ON loc.cell_no = m.cell_no
WHERE
      loc.zone_no = ‘B12‘
                AND loc.WMS_PICKING_FLAG = ‘cp‘
                AND m.cell_no in (SELECT cell_no FROM st_stock_m WHERE goods_no IN (‘1230480‘))

因为开发对这块的逻辑也不是很清楚,不分析逻辑上是否可以直接goods_no拿出来直接约束结果集,单纯从in子查询无法使用到索引来看MySQL优化器是如何去处理的

SELECT     `ma`.`loc`.`CELL_NO` AS `m_cellNo`     FROM `ma`.`bs_loc` `loc` JOIN `ma`.`st_stock_m` `m`     WHERE       ((`ma`.`loc`.`ZONE_NO` =‘B33‘) AND<in_optimizer>(`ma`.`m`.`CELL_NO`,      <EXISTS>         (SELECT1FROM `ma`.`st_stock_m` WHERE ((`ma`.`st_stock_m`.`GOODS_NO` =‘1230480‘) AND (<CACHE>(`ma`.`m`.`CELL_NO`) = `ma`.`st_stock_m`.`CELL_NO`))))         AND (`ma`.`loc`.`CELL_NO` = `ma`.`m`.`CELL_NO`))

执行计划

其实子查询返回的结果集最多不会超过3个,通常我们认为内部会按照使用结果集逐一去查,效率会很快,但实际上不是

以为内部的操作会是

步骤1:
SELECT group_concat(cell_no) FROM st_stock_m WHERE goods_no IN (‘1230480‘) into @cell_no;
步骤2
SELECT
        loc.cell_no             AS m_cellNo
        ...

        FROM bs_loc loc LEFT JOIN st_stock_m m ON loc.cell_no = m.cell_no
        WHERE
      loc.zone_no = ‘B12‘
                AND loc.WMS_PICKING_FLAG = ‘cp‘
                AND m.cell_no in (@cell_no);

按照《高性能MySQL》中所说:

把这个查询拿到MariaDB测试了一下,确实要比MySQL 5.5.18处理效果好很多。

SELECT     `ma`.`loc`.`CELL_NO` AS `m_cellNo`     FROM `ma`.`bs_loc` `loc` semi JOIN (`ma`.`st_stock_m`) JOIN `ma`.`st_stock_m` `m`     WHERE       (        (`ma`.`m`.`CELL_NO` = `ma`.`st_stock_m`.`CELL_NO`) AND         (`ma`.`loc`.`ZONE_NO` =‘B33‘) AND         (`ma`.`st_stock_m`.`GOODS_NO` =‘1230480‘) AND         (`ma`.`loc`.`CELL_NO` = `ma`.`st_stock_m`.`CELL_NO`)      )

执行计划

MariaDB优化器改写后使用的semi join,这块MariaDB官网有部分说明:

https://mariadb.com/kb/en/mariadb/semi-join-materialization-strategy/

《MySQL技术内幕:SQL编程》中对于MariaDB优化器对于子查询和join的优化部分有说明

其他博文对于MySQL5.5以及MariaDB5.3优化器对比的文章:

http://blog.sina.com.cn/s/blog_aa8dc60801012pzc.html

http://www.server110.com/mariadb/201310/2245.html

时间: 2024-10-11 00:45:20

【MySQL】MySQL/MariaDB的优化器对in子查询的处理的相关文章

MYSQL优化派生表(子查询)在From语句中的

Mysql 在5.6.3中,优化器更有效率地处理派生表(在from语句中的子查询): 优化器推迟物化子查询在from语句中的子查询,知道子查询的内容在查询正真执行需要时,才开始物化.这一举措提高了性能: 1:之前版本(5.6.3),from语句中的子查询在explain select 查看执行计划语句执行时就会物化.它导致了部分查询执行,但explain语句的目的是获取执行计划信息,而不是执行查询 该版本物化不会在explain中发生,所以explain执行计划结果的得到更快: 2:因为上面提及

mysql常用基础操作语法(十)~~子查询【命令行模式】

mysql中虽然有连接查询实现多表连接查询,但是连接查询的性能很差,因此便出现了子查询. 1.理论上,子查询可以出现在查询语句的任何位置,但实际应用中多出现在from后和where后.出现在from后的子查询结果通常是多行多列的,充当临时表:而出现在where后的子查询结果通常是单行单列,充当条件: 2.where后作为条件的子查询多与"="."!=".">"."<"等比较运算符一起使用.结果虽然通常是单行单列,但

【MYSQL】update/delete/select语句中的子查询

update或delete语句里含有子查询时,子查询里的表不能在update或是delete语句中,如含有运行时会报错:但select语句里含有子查询时,子查询里的表可以在select语句中. 如:把总成绩小于100的学生名称修改为天才 select stu_id from score group by stu_id having sum(grade)<100; #查询总成绩小于100的学生IDupdate students set name='天才' where id in (select s

MySQL5.7性能优化系列(二)——SQL语句优化(3)——使用物化策略优化子查询

优化器使用物化策略(Materialization)来实现更有效的子查询处理.通过生成子查询结果作为临时表,通常在内存中,实现加速查询执行. MySQL首次需要子查询结果,将该结果实现为临时表.任何随后的结果都需要,MySQL再次指向临时表.优化器可以使用散列索引对表进行索引,以使查找更加快速和便宜.该索引是唯一的,它消除了重复,并使表格更小. 子查询实现可能时使用内存中临时表,如果表变得太大,则返回到磁盘存储. 如果不使用物化策略,则优化器有时将非相关子查询重写为相关子查询.例如,以下IN子查

[MySQL Reference Manual] 8 优化

8.优化 8.优化... 1 8.1 优化概述... 1 8.2 优化SQL语句... 1 8.2.1 优化SELECT语句... 1 8.2.1.1 SELECT语句的速度... 1 8.2.1.2 WHERE子句优化... 1 8.2.1.3 Range优化... 1 8.2.1.4 索引合并(Index Merge)优化... 1 8.2.1.5 引擎Pushdown条件优化... 1 8.2.1.6 索引条件Pushdown优化... 1 8.2.1.7 使用索引扩展... 1 8.2.

MySql学习(六) —— 数据库优化理论(二) —— 查询优化技术

逻辑查询优化包括的技术 1)子查询优化  2)视图重写  3)等价谓词重写  4)条件简化  5)外连接消除  6)嵌套连接消除  7)连接消除  8)语义优化 9)非SPJ优化 一.子查询优化 1. 什么是子查询:当一个查询是另一个查询的子部分时,称之为子查询. 2. 查询的子部分,包含的情况: a) 目标列位置:子查询如果位于目标列,则只能是标量子查询,否则数据库可能返回类似“错误:子查询只能返回一个字段 ( [Err] 1242 - Subquery returns more than 1

美图秀秀DBA谈MySQL运维及优化

https://mp.weixin.qq.com/s?__biz=MzI4NTA1MDEwNg==&mid=401797597&idx=2&sn=a0fc08dbb8ce399f0d4cd70bff5b1366&scene=0&key=62bb001fdbc364e56abc83575de147aa1f6fe32d5f4bad7190eadb03350bcfba18b0c9740d43855a5b45e5286bd457cd&ascene=7&uin

使用连接(JOIN)来代替子查询(Sub-Queries) mysql优化系列记录

使用连接(JOIN)来代替子查询(Sub-Queries) MySQL从4.1开始支持SQL的子查询.这个技术可以使用SELECT语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中.例如,我们要将客户基本信息表中没有任何订单的客户删除掉,就可以利用子查询先从销售信息表中将所有发出订单的客户ID取出来,然后将结果传递给主查询,如下所示: DELETE FROM customerinfo WHERE CustomerID NOT in (SELECT CustomerID FR

MySQL里面的子查询

一.子查询定义 定义: 子查询允许把一个查询嵌套在另一个查询当中. 子查询,又叫内部查询,相对于内部查询,包含内部查询的就称为外部查询. 子查询可以包含普通select可以包括的任何子句,比如:distinct. group by.order by.limit.join和union等:但是对应的外部查询必须是以下语句之一:select.insert.update.delete.set或 者do. 子查询的位置: select 中.from 后.where 中.group by 和order by