mysql子查询慢的问题

  当你在用explain工具查看sql语句的执行计划时,若select_type 字段中出现“DEPENDENT SUBQUERY”时,你要注意了,你已经掉入了mysql子查询慢的“坑"。。。下面我们来看一个具体的例子

有这样一条查询语句:

SELECT gid,COUNT(id) as count FROM shop_goods g1 WHERE status =0 and gid IN (SELECT gid FROM shop_goods g2 WHERE sid IN  (1519066,1466114,1466110,1466102,1466071,1453929))GROUP BY gid;

用explain看了一下,出现关键字“DEPENDENT SUBQUERY”,意味着子查询的第一个select依赖外部的查询;

SUBQUERY:子查询中的第一个SELECT;DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询 。

换句话说,就是 子查询对 g2 的查询方式依赖于外层 g1 的查询。它意味着两步:

第一步,MySQL 根据 select gid,count(id) from shop_goods where status=0 group by gid; 得到一个大结果集 t1,其数据量为rows=850672 了;

第二步,上面的大结果集 t1 中的每一条记录,都将与子查询 SQL 组成新的查询语句:select gid from shop_goods where sid in (15...blabla..29) and gid=%t1.gid%。等于说,子查询要执行85万次……即使这两步查询都用到了索引,但不慢才怪;

如此一来,子查询的执行效率居然受制于外层查询的记录数,那还不如拆成两个独立查询顺序执行呢。

对于此类语句一般的优化策略是拆成两个查询语句,你不想拆成两个独立查询的话,也可以与临时表join查询,:

你不想拆成两个独立查询的话,也可以与临时表联表查询,如下所示优化后的sql:

SELECT g1.gid,count(1) FROM shop_goods g1,(select gid from shop_goods WHERE sid in (1519066,1466114,1466110,1466102,1466071,1453929)) g2 where g1.status=0 and g1.gid=g2.gid GROUP BY g1.gid;

用explain看了一下,这次又有了一个新的关键字"DERIVED",意思是用于 from 子句里有子查询的情况。MySQL 会递归执行这些子查询,把结果放在临时表里,然后再做join操作;

DERIVED 的官方含义为:用于 from 子句里有子查询的情况。MySQL 会递归执行这些子查询,把结果放在临时表里。

《高性能MySQL》的第4.4节“MySQL查询优化器的限制(Limitations of the MySQL Query Optimizer)”之第4.4.1小节“关联子查询(Correlated Subqueries)”也有类似的论述:mysql 在处理子查询时,会改写子查询。通常情况下,我们希望由内到外,先完成子查询的结果,然后再用子查询来驱动外查询的表,完成查询。

例如:select * from test where tid in(select fk_tid from sub_test where gid=10);通常我们会感性地认为该 sql 的执行顺序是:sub_test 表中根据 gid 取得 fk_tid(2,3,4,5,6)记录,然后再到 test 中,带入 tid=2,3,4,5,6,取得查询数据。

但是实际mysql的处理方式为:

select * from test where exists (select * from sub_test where gid=10 and sub_test.fk_tid=test.tid);

mysql 将会扫描 test 中所有数据,每条数据都将会传到子查询中与 sub_test 关联,子查询不会先被执行,所以如果 test 表很大的话,那么性能上将会出现问题。

时间: 2024-09-11 11:30:36

mysql子查询慢的问题的相关文章

sql性能优化-mysql子查询是否被重复执行?

问题描述 mysql子查询是否被重复执行? 请教!mysql返回固定结果集时,是否被重复执行 例如1:select t.*,(select count(1) from table01) from table01 t; 例如2:select t.*,(select count(1) from table01 t2 where t2.key=t1.key) from table01 t1 ;--像这种嵌套的子查询是会被重复执行的. 疑问:上面例子1中的子查询遍历过程中,都是固定结果集,会被重复执行N

MySQL子查询用法实例分析_Mysql

本文实例讲述了MySQL子查询用法.分享给大家供大家参考,具体如下: 假设表my_tbl包含三个字段a,b,c:现在需要查询表中列a的每个不同值下的列b为最小值的记录量. 比如表记录为: a  b  c 1  3  'cd' 2  3  'nhd' 1  5  'bg' 2  6  'cds' 1  7  'kiy' 3  7  'vsd' 3  8  'ndf' 希望得到结果为: a  b  c 1  3  'cd' 2  3  'nhd' 3  7  'vsd' (1) 其中一个做法:先查出

MySQL子查询的几种常见形式介绍_Mysql

mysql子查询的几种常见写法: 复制代码 代码如下: select * from xxx where col = [any|all](select * from xxxx);   该句法可分为加关键词和不加关键词的写法,当不加关键词的时候,子查询语句返回的是一个离散值(注意是一个),查询语句将以子查询语句的结果作为自己 where子句的条件进行查询,该句法可以在子查询语句前加入any.all.some等关键字,此时子查询语句返回的是一组离散值.any则表示,查询语句是以子查询返回的值作为一个范

mysql子查询where/having/in/exists/from例子

where/having查询 MySQL可以在where子句或者having子句中包含子查询.包含在圆括号内的子查询,优先级高于比较和逻辑操作符.in操作符或者 exists操作符. 也可以在一个having子句中的比较运算符前使用子查询,从而用它对父查询创建的组进行过滤. where和having的区别 HAVING是先分组再筛选记录,WHERE在聚合前先筛选记录.也就是说作用在GROUP BY 子句和HAVING子句前:而 HAVING子句在聚合后对组记录进行筛选. 作用的对象不同.WHER

对MySQL子查询的简单改写优化_Mysql

使用过oracle或者其他关系数据库的DBA或者开发人员都有这样的经验,在子查询上都认为数据库已经做过优化,能够很好的选择驱动表执行,然后在把该经验移植到mysql数据库上,但是不幸的是,mysql在子查询的处理上有可能会让你大失所望,在我们的生产系统上就由于碰到了这个问题: select i_id, sum(i_sell) as i_sell from table_data where i_id in (select i_id from table_data where Gmt_create

MYSQL子查询与连接

37:子查询与连接SET 列名 gbk;//改变客户端数据表的编码类型. 子查询子查询(Subquery)是指出现在其他SQL语句内的SELECT子句例如SELECT * FROM t1 WHERE col1=(SELECT col2 FROM t2);其中SELECT * FROM t1称为Outer Query/Outer StatementSELECT col2 FROM FROM t2,称为SubQuery 子查询指嵌套在查询内部,且必须始终出现在圆括号内.子查询可以包含多个关键字或者条

Mysql子查询和联合(UNION)查询详解

查询:  在select查询中,又嵌套了一个select查询.一个是外层查询,另一个是内层查询. Where子查询 就是在where查询语句有一个select语句,把内层查询的结果当做外层查询的条件. From子查询 在from 查询语句中,有一个select语句,把内层查询结果作为一张临时表,供外层再一次查询. 区别: 对于不是唯一取值的列,使用where子查可能会出现不正确的结果.如果用from,有分组的情况下,我们要通过排序把需要的记录放在第一的位置上. Exists #查询有商品的栏目

Mysql子查询

问题描述 有谁可以解释一下这段查询的意思? SELECT * FROM table1 t1  WHERE 1=1  and t1_id in (select table1_id from table2 t2 where 1=1  and (t2.t2_name like '%wangwu%'  or  t1.t1_name like '%zhansan%') ); table1  +---------------------+| t1_id |   t1_name   |+-----------

mySQL子查询拿不出数据

问题描述 我的mySQL是5.0版本的可是select * from rights where id not in ( select id from rights limit 80) limit 10;这句还是说不支持这是为什么呢? 解决方案 首先 你的版本可能太低了不支持这个子查询:当然我的也不支持 所以出错引用This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'如果你的 意思是分页 或者查询第