MySQL in查询优化

https://blog.csdn.net/gua___gua/article/details/47401621

MySQL in查询优化<一>

原创 2015年08月10日 17:57:56

  • 5137

开发说他写了个SQL特别慢,让看看。

[html] view plain copy

  1. select * from t_channel where id_ in(select distinct cdbh from sjkk_gcjl where jgsj>‘2015-01-02 08:00:00‘ and jgsj<‘2015-01-02 12:00:00‘);
  2. ......
  3. 30min+

然后我查询内部SQL,只需要3s+

[html] view plain copy

  1. mysql> select distinct cdbh from sjkk_gcjl where jgsj>‘2015-01-02 08:00:00‘ and jgsj<‘2015-01-02 12:00:00‘;
  2. .....
  3. 1755 rows in set (3.30 sec)
  4. mysql> select count(*) from t_channel;
  5. ....
  6. 12062 rows in set (0.70 sec)

开发写的SQL为啥那么慢呢?看看执行计划

[html] view plain copy

  1. explain extended select * from t_channel where id_ in(select distinct cdbh from sjkk_gcjl where jgsj>‘2015-01-02 08:00:00‘ and jgsj<‘2015-01-02 12:00:00‘);
  2. +----+--------------------+-----------+-------+---------------+----------+---------+------+--------+----------+------------------------------+
  3. | id | select_type        | table     | type  | possible_keys | key      | key_len | ref  | rows   | filtered | Extra                        |
  4. +----+--------------------+-----------+-------+---------------+----------+---------+------+--------+----------+------------------------------+
  5. |  1 | PRIMARY            | t_channel | ALL   | NULL          | NULL     | NULL    | NULL |  12062 |   100.00 | Using where                  |
  6. |  2 | DEPENDENT SUBQUERY | sjkk_gcjl | range | idx_jgsj      | idx_jgsj | 8       | NULL | 731868 |   100.00 | Using where; Using temporary |
  7. +----+--------------------+-----------+-------+---------------+----------+---------+------+--------+----------+------------------------------

看看数据库转换后的语句

[html] view plain copy

  1. mysql> show warnings;
  2. SELECT
  3. `shanghai_full`.`t_channel`.`ID_` AS `ID_`,
  4. `shanghai_full`.`t_channel`.`Code_` AS `Code_`,
  5. ...... --这里会列出所有字段
  6. FROM
  7. `shanghai_full`.`t_channel`
  8. WHERE
  9. < in_optimizer > (
  10. `shanghai_full`.`t_channel`.`ID_` ,< EXISTS > (
  11. SELECT DISTINCT
  12. 1
  13. FROM
  14. `shanghai_full`.`sjkk_gcjl`
  15. WHERE
  16. (
  17. (
  18. `shanghai_full`.`sjkk_gcjl`.`jgsj` > ‘2015-01-02 08:00:00‘
  19. )
  20. AND (
  21. `shanghai_full`.`sjkk_gcjl`.`jgsj` < ‘2015-01-02 12:00:00‘
  22. )
  23. AND (
  24. < CACHE > (
  25. `shanghai_full`.`t_channel`.`ID_`
  26. ) = `shanghai_full`.`sjkk_gcjl`.`cdbh`
  27. )
  28. )
  29. )
  30. );

可见,经过mysql优化器后,in 给转换成exists的方式(mysql认为换成exists更快,呵呵)。

慢的原因:走了exists,查询把外表t_channel做为主表进行全表扫描,每扫描一行数据,然后对子查询进行查询看这条数据是否符合条件。

特别说明:mysql版本是5.5。在5.6中mysql做了改进,将in的这种查询转换为了join。

优化方式一(将in查询转换为连接查询)

[html] view plain copy

  1. select t1.* from t_channel t1,(select distinct cdbh from sjkk_gcjl where jgsj>‘2015-01-02 08:00:00‘ and jgsj<‘2015-01-02 12:00:00‘) t2 where t1.id_=t2.cdbh;
  2. ......
  3. 1264 rows in set (3.30 sec)
  4. mysql> explain extended select t1.* from t_channel t1,(select distinct cdbh from sjkk_gcjl where jgsj>‘2015-01-02 08:00:00‘ and jgsj<‘2015-01-02 12:00:00‘) t2 where t1.id_www.255055.cn/ =t2.cdbh;
  5. +----+-------------+------------+--------+---------------+----------+---------+---------+--------+----------+------------------------------+
  6. | id | select_type | table      | type   | possible_keys | key      | key_len | ref     | rows   | filtered | Extra                        |
  7. +----+-------------+------------+--------+---------------+----------+---------+---------+--------+----------+------------------------------+
  8. |  1 | PRIMARY     | <derived2> | ALL    | NULL          | NULL     | NULL    | NULL    |   1755 |   100.00 |                              |
  9. |  1 | PRIMARY     | t1    www.boshenyl.cn      | eq_ref | PRIMARY,ID_   | PRIMARY  | 74      | t2.cdbh |      1 |   100.00 | Using where                  |
  10. |  2 | DERIVED     | sjkk_gcjl  | range  | idx_jgsj      | idx_jgsj | 8       | NULL    | 731868 |   100.00 | Using where; Using temporary |
  11. +----+-------------+------------+--------+---------------+----------+---------+---------+--------+----------+------------------------------+
  12. mysql> show warnings;
  13. SELECT
  14. `shanghai_full`.`t1`.`ID_` AS `ID_`,
  15. ........ ---这里会列出所有字段FROM
  16. `shanghai_full`.`t_channel` `t1`
  17. JOIN (
  18. SELECT DISTINCT
  19. `shanghai_full`.`sjkk_gcjl`.`cdbh` AS `www.cnzhaotai.com cdbh`
  20. FROM
  21. `shanghai_full`.www.fengshen157.com `sjkk_gcjl`
  22. WHERE
  23. (
  24. (
  25. `shanghai_full`.`sjkk_gcjl`.`jgsj` > ‘2015-01-02 08:00:00‘
  26. )
  27. AND (
  28. `shanghai_full`.`sjkk_gcjl`.`jgsj` < ‘2015-01-02 12:00:00‘
  29. )
  30. )
  31. ) `t2`
  32. WHERE
  33. (
  34. `shanghai_full`.`t1`.`ID_` = www.taohuayuan178.com `t2`.`cdbh`
  35. );

优化方式二(使用memory引擎的临时表)

[html] view plain copy

  1. mysql> create temporary table tmp_www.yibaoyule1.com channel  engine=memory (select distinct cdbh from sjkk_gcjl where jgsj>‘2015-01-02 08:00:00‘ and jgsj<‘2015-01-02 12:00:00‘);
  2. Query OK, 1755 rows affected (9.00 sec)
  3. Records: 1755  Duplicates: 0  Warnings: 0
  4. mysql> select * from t_channel where id_ in(select * from tmp_channel);
  5. .....
  6. 1264 rows in set (0.26 sec)
  7. mysql> explain extended select * from t_channel where id_ in(select * from tmp_channel);
  8. +----+--------------------+-------------+------+---------------+------+---------+------+------+----------+-------------+
  9. | id | select_type        | table       | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
  10. +----+--------------------+-------------+------+---------------+------+---------+------+------+----------+-------------+
  11. |  1 | PRIMARY            | t_channel   | ALL  | NULL          | NULL | NULL    | NULL | 3224 |   100.00 | Using where |
  12. |  2 | DEPENDENT SUBQUERY | tmp_channel | ALL  | NULL          | NULL | NULL    | NULL |   20 |   100.00 | Using where |
  13. +----+--------------------+-------------+------+---------------+------+---------+------+------+----------+-------------+
  14. mysql> show warnings;
  15. | Note  | 1003 | select `vmc_jiaqi`.`t_channel`.`ID_` AS `ID_`,`vmc_jiaqi`.`t_channel`.`Code_` AS `Code_`,`vmc_jiaqi`.`t_channel`.`HostId_` AS `HostId_`,`vmc_jiaqi`.`t_channel`.`RoadMonitorStationId_` AS `RoadMonitorStationId_`,`vmc_jiaqi`.`t_channel`.`ChannelNo_` AS `ChannelNo_`,`vmc_jiaqi`.`t_channel`.`Name_` AS `Name_`,`vmc_jiaqi`.`t_channel`.`ChannelType_` AS `ChannelType_`,`vmc_jiaqi`.`t_channel`.`Ext_` AS `Ext_`,`vmc_jiaqi`.`t_channel`.`DeviceAddress_` AS `DeviceAddress_`,`vmc_jiaqi`.`t_channel`.`MinSpeed_`www.mhylpt.comS `MinSpeed_`,`vmc_jiaqi`.`t_channel`.`MaxSpeed_` AS `MaxSpeed_`,`vmc_jiaqi`.`t_channel`.`LimitMinRatio_` AS `LimitMinRatio_`,`vmc_jiaqi`.`t_channel`.`LimitMaxRatio_` AS `LimitMaxRatio_`,`vmc_jiaqi`.`t_channel`.`Direction_` AS `Direction_`,`vmc_jiaqi`.`t_channel`.`JcDirection_` AS `JcDirection_`,`vmc_jiaqi`.`t_channel`.`LaneNum_` AS `LaneNum_`,`vmc_jiaqi`.`t_channel`.`FrameDropNum_` AS `FrameDropNum_`,`vmc_jiaqi`.`t_channel`.`RecogizeRectLeft_` AS `RecogizeRectLeft_`,`vmc_jiaqi`.`t_channel`.`RecogizeRectTop_` AS `RecogizeRectTop_`,`vmc_jiaqi`.`t_channel`.`RecogizeRectWidth_` AS `RecogizeRectWidth_`,`vmc_jiaqi`.`t_channel`.`RecogizeRectHeight_` AS `RecogizeRectHeight_`,`vmc_jiaqi`.`t_channel`.`RmpServerIp_` AS `RmpServerIp_`,`vmc_jiaqi`.`t_channel`.`RmpServerPort_` AS `RmpServerPort_`,`vmc_jiaqi`.`t_channel`.`VirtualGateServerId_` AS `VirtualGateServerId_`,`vmc_jiaqi`.`t_channel`.`LaneType_` AS `LaneType_`,`vmc_jiaqi`.`t_channel`.`DeviceType_` AS `DeviceType_`,`vmc_jiaqi`.`t_channel`.`ManufacturerId_` AS `ManufacturerId_`,`vmc_jiaqi`.`t_channel`.`IsLocalSavePicture_` AS `IsLocalSavePicture_`,`vmc_jiaqi`.`t_channel`.`OrderNO_` AS `OrderNO_`,`vmc_jiaqi`.`t_channel`.`channelStatus` AS `channelStatus` from `vmc_jiaqi`.`t_channel` where <in_optimizer>(`vmc_jiaqi`.`t_channel`.`ID_`,<exists>(select 1 from `vmc_jiaqi`.`tmp_channel` where (<cache>(`vmc_jiaqi`.`t_channel`.`ID_`) = `vmc_jiaqi`.`tmp_channel`.`cdbh`)))

注意:第二种方式还是使用了exists的执行方式,所以这种方式没有第一种方式好,在特定的条件下可能会有用处,

原文地址:https://www.cnblogs.com/qwangxiao/p/8903870.html

时间: 2024-10-09 11:01:30

MySQL in查询优化的相关文章

查询优化 | MySQL慢查询优化

?Explain查询:rows,定位性能瓶颈. 只需要一行数据时,使用LIMIT1. 在搜索字段上建立索引. 使用ENUM而非VARCHAR. 选择区分度高的列作为索引. 采用扩展索引,而不是新建索引. 慢查询日志:log-slow-queries,mysqldumpslow工具. 避免select * 尽可能使用NOT NULL where中避免索引无效. <MySQL索引原理及慢查询优化>    http://tech.meituan.com/mysql-index.html [查询语句的

php mysql 一个查询优化的简单例子

PHP+Mysql是一个最经常使用的黄金搭档,它们俩配合使用,能够发挥出最佳性能,当然,如果配合Apache使用,就更加Perfect了. 因此,需要做好对mysql的查询优化.下面通过一个简单的例子,展现不同的SQL语句对于查询速度的影响: 存在这样的一张表test,它有一个自增的id作为主索引.现在要查询id号处于某一个范围内的记录,可以使用如下SQL语句:  代码如下 复制代码 SELECT *FROM `test`order by id asclimit 208888,50 这条SQL语

MySQL 慢查询优化

为什么查询速度会慢 1.慢是指一个查询的响应时间长.一个查询的过程: 客户端发送一条查询给服务器 服务器端先检查查询缓存,如果命中了缓存,则立可返回存储在缓存中的结果.否则进入下一个阶段 服务器端进行SQL解析.预处理,再由优化器生成对应的执行计划. MySQL根据优化器生成的执行计划,调用存储引擎的API来执行查询. 将结果返回给客户端 2.数据访问 是否向数据库请求了不需要的数据 是否扫描额外的记录 3.查询的方式 一个复杂的查询还是多个简单的查询 切分查询(将大查询切分成小查询,循环完成小

MySQL物理查询优化技术---index dive辨析

一 引子 在MySQL的官方手册上有这么一句话: the optimizer can estimate the row count for each range using dives into the index or index statistics. 这是在说: 优化器为每一个范围段(如"a IN (10, 20, 30)"是等值比较, 括3个范围段实则简化为3个单值,分别是10,20,30)估计每个范围段(用范围段来表示是因为MySQL的"range"扫描方

MySql中查询优化方法

最近一段时间由于工作需要,开始关注针对Mysql数据库的select查询语句的相关优化方法. 由于在参与的实际项目中发现当mysql表的数据量达到百万级时,普通SQL查询效率呈直线下降,而且如果where中的查询条件较多时,其查询速度简直无法容忍.曾经测试对一个包含400多万条记录(有索引)的表执行一条条件查询,其查询时间竟然高达40几秒,相信这么高的查询延时,任何用户都会抓狂.因此如何提高sql语句查询效率,显得十分重要.以下是网上流传比较广泛的30种SQL查询语句优化方法: 1.应尽量避免在

MySQL慢查询优化最佳实践(一)

慢查询 我们知道,一般的应用系统,MySQL的读写比例在10:1左右,而且一般的插入和更新操作很少会出现性能问题,遇到问题最多的,也是最容易出现问题的,还是一些复杂的查询操作,所以查询语句的优化已经成为开发.运维工程师们的必须课,是大部分运维工作之中的重中之重. 索引原理 数据库建立索引的目的是为了提高查询效率,索引如同生活中的字典.列车时刻表.图书目录一样,原理都相同,都是通过不断缩小想要获得的数据范围来筛选出最终想要的结果,把本来是随机查询的事件变成有序的事件,如我们在字典里查"mysql&

mysql 子查询优化一例

写在前面的话: 在慢查优化1和2里都反复强调过 explain 的重要性,但有时候肉眼看不出 explain 结果如何指导优化,这时候还需要有一些其他基础知识的佐助,甚至需要了解 MySQL 实现原理,如子查询慢查优化. 看到 SQL 执行计划中 select_type 字段中出现"DEPENDENT SUBQUERY"时,要打起精神了! --MySQL 的子查询为什么有时候很糟糕-- 引子:这样的子查询为什么这么慢? 下面的例子是一个慢查,线上执行时间相当夸张.为什么呢? SELEC

mysql慢查询优化之explain的各列含义

mysql> explain select customer_id,first_name,last_name from customer; +----+-------------+----------+------+---------------+------+---------+------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra

MySQL之查询优化方式(笔记)

1.COUNT() 对COUNT的优化可以通过下面的SQL实现 mysql> select count(gnp<10000 or null) as '<<<<',count(gnp>=10000 or null) as '>>>>' from country; +------+------+ | <<<< | >>>> | +------+------+ | 152 | 87 | +-----