MySQL性能优化小记:MySQL子查询很慢的问题

今天碰到一个数据库问题,需要用到子查询,但尝试了一下发现它很慢:


mysql> select * from abc_number_prop where number_id in (select number_id from abc_number_phone where phone = '82306839');

为了节省篇幅,省略了输出内容,下同。

67 rows in set (12.00 sec)


只有67行数据返回,却花了12秒,而系统中可能同时会有很多这样的查询,系统肯定扛不住。用desc看一下(注:explain也可)


mysql> desc select * from abc_number_prop where number_id in (select number_id from abc_number_phone where phone = '82306839');
+----+--------------------+------------------+--------+-----------------+-------+---------+------------+---------+--------------------------+
| id | select_type        | table            | type   | possible_keys   | key   | key_len | ref        | rows    | Extra                    |
+----+--------------------+------------------+--------+-----------------+-------+---------+------------+---------+--------------------------+
|  1 | PRIMARY            | abc_number_prop  | ALL    | NULL            | NULL  | NULL    | NULL       | 2679838 | Using where              |
|  2 | DEPENDENT SUBQUERY | abc_number_phone | eq_ref | phone,number_id | phone | 70      | const,func |       1 | Using where; Using index |
+----+--------------------+------------------+--------+-----------------+-------+---------+------------+---------+--------------------------+
2 rows in set (0.00 sec)


从上面的信息可以看出,在执行此查询时会扫描两百多万行,难道是没有创建索引吗,看一下


mysql> show index from abc_number_phone;
+------------------+------------+-------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table            | Non_unique | Key_name    | Seq_in_index | Column_name     | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------------+------------+-------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| abc_number_phone |          0 | PRIMARY     |            1 | number_phone_id | A         |       36879 |     NULL | NULL   |      | BTREE      |         |               |
| abc_number_phone |          0 | phone       |            1 | phone           | A         |       36879 |     NULL | NULL   |      | BTREE      |         |               |
| abc_number_phone |          0 | phone       |            2 | number_id       | A         |       36879 |     NULL | NULL   |      | BTREE      |         |               |
| abc_number_phone |          1 | number_id   |            1 | number_id       | A         |       36879 |     NULL | NULL   |      | BTREE      |         |               |
| abc_number_phone |          1 | created_by  |            1 | created_by      | A         |       36879 |     NULL | NULL   |      | BTREE      |         |               |
| abc_number_phone |          1 | modified_by |            1 | modified_by     | A         |       36879 |     NULL | NULL   | YES  | BTREE      |         |               |
+------------------+------------+-------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
6 rows in set (0.06 sec)

mysql> show index from abc_number_prop;
+-----------------+------------+-------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table           | Non_unique | Key_name    | Seq_in_index | Column_name    | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------------+------------+-------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| abc_number_prop |          0 | PRIMARY     |            1 | number_prop_id | A         |      311268 |     NULL | NULL   |      | BTREE      |         |               |
| abc_number_prop |          1 | number_id   |            1 | number_id      | A         |      311268 |     NULL | NULL   |      | BTREE      |         |               |
| abc_number_prop |          1 | created_by  |            1 | created_by     | A         |      311268 |     NULL | NULL   |      | BTREE      |         |               |
| abc_number_prop |          1 | modified_by |            1 | modified_by    | A         |      311268 |     NULL | NULL   | YES  | BTREE      |         |               |
+-----------------+------------+-------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
4 rows in set (0.15 sec)


从上面的输出可以看出,这两张表在number_id字段上创建了索引的。


看看子查询本身有没有问题。

mysql> desc select number_id from abc_number_phone where phone = '82306839';
+----+-------------+------------------+------+---------------+-------+---------+-------+------+--------------------------+
| id | select_type | table            | type | possible_keys | key   | key_len | ref   | rows | Extra                    |
+----+-------------+------------------+------+---------------+-------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | abc_number_phone | ref  | phone         | phone | 66      | const |    6 | Using where; Using index |
+----+-------------+------------------+------+---------------+-------+---------+-------+------+--------------------------+
1 row in set (0.00 sec)


没有问题,只需要扫描几行数据,索引起作用了。查询出来看看

mysql> select number_id from abc_number_phone where phone = '82306839';
+-----------+
| number_id |
+-----------+
|      8585 |
|     10720 |
|    148644 |
|    151307 |
|    170691 |
|    221897 |
+-----------+
6 rows in set (0.00 sec)


直接把子查询得到的数据放到上面的查询中

mysql> select * from abc_number_prop where number_id in (8585, 10720, 148644, 151307, 170691, 221897);

67 rows in set (0.03 sec)


速度也快,看来MySQL在处理子查询的时候是不够好。我在MySQL 5.1.42 和 MySQL 5.5.19 都进行了尝试,都有这个问题。


搜索了一下网络,发现很多人都遇到过这个问题:

参考资料1:使用连接(JOIN)来代替子查询(Sub-Queries) mysql优化系列记录
http://blog.youkuaiyun.com/hongsejiaozhu/article/details/1876181
参考资料2:网站开发日记(14)-MYSQL子查询和嵌套查询优化
http://dodomail.iteye.com/blog/250199

 

根据网上这些资料的建议,改用join来试试。

修改前:select * from abc_number_prop where number_id in (select number_id from abc_number_phone where phone = '82306839');

修改后:select a.* from abc_number_prop a inner join abc_number_phone b on a.number_id = b.number_id where phone = '82306839';


mysql> select a.* from abc_number_prop a inner join abc_number_phone b on a.number_id = b.number_id where phone = '82306839';

67 rows in set (0.00 sec)


效果不错,查询所用时间几乎为0。看一下MySQL是怎么执行这个查询的


mysql> desc select a.* from abc_number_prop a inner join abc_number_phone b on a.number_id = b.number_id where phone = '82306839';
+----+-------------+-------+------+-----------------+-----------+---------+-----------------+------+--------------------------+
| id | select_type | table | type | possible_keys   | key       | key_len | ref             | rows | Extra                    |
+----+-------------+-------+------+-----------------+-----------+---------+-----------------+------+--------------------------+
|  1 | SIMPLE      | b     | ref  | phone,number_id | phone     | 66      | const           |    6 | Using where; Using index |
|  1 | SIMPLE      | a     | ref  | number_id       | number_id | 4       | eap.b.number_id |    3 |                          |
+----+-------------+-------+------+-----------------+-----------+---------+-----------------+------+--------------------------+
2 rows in set (0.00 sec)


小结:当子查询速度慢时,可用JOIN来改写一下该查询来进行优化。


网上也有文章说,使用JOIN语句的查询不一定总比使用子查询的语句快。

参考资料3:改变了对Mysql子查询的看法
http://hi.baidu.com/yzx110/blog/item/e694f536f92075360b55a92b.html


本文链接:http://codingstandards.iteye.com/blog/1344833


正好手头有本《高性能MySQL》,翻阅了一下,第4.4节“MySQL查询优化器的限制”4.4.1小节“关联子查询”正好讲到这个问题。


MySQL有时优化子查询很差,特别是在WHERE从句中的IN()子查询。像上面我碰到的情况,其实我的想法是MySQL会把

select * from abc_number_prop where number_id in (select number_id from abc_number_phone where phone = '82306839');

变成下面的样子

select * from abc_number_prop where number_id in (8585, 10720, 148644, 151307, 170691, 221897);

但不幸的是,实际情况正好相反。MySQL试图让它和外面的表产生联系来“帮助”优化查询,它认为下面的exists形式更有效率

select * from abc_number_prop where exists (select * from abc_number_phone where phone = ' 82306839' and number_id = abc_number_prop.number_id);


mysql> select * from abc_number_prop where exists (select * from abc_number_phone where phone = '82306839' and number_id = abc_number_prop.number_id);

67 rows in set (10.89 sec)


mysql> desc select * from abc_number_prop where exists (select * from abc_number_phone where phone = '82306839' and number_id = abc_number_prop.number_id);
+----+--------------------+------------------+--------+-----------------+-------+---------+-------------------------------------+---------+--------------------------+
| id | select_type        | table            | type   | possible_keys   | key   | key_len | ref                                 | rows    | Extra                    |
+----+--------------------+------------------+--------+-----------------+-------+---------+-------------------------------------+---------+--------------------------+
|  1 | PRIMARY            | abc_number_prop  | ALL    | NULL            | NULL  | NULL    | NULL                                | 2660707 | Using where              |
|  2 | DEPENDENT SUBQUERY | abc_number_phone | eq_ref | phone,number_id | phone | 70      | const,eap.abc_number_prop.number_id |       1 | Using where; Using index |
+----+--------------------+------------------+--------+-----------------+-------+---------+-------------------------------------+---------+--------------------------+
2 rows in set (0.01 sec)


这种in子查询的形式,在外部表(比如上面的abc_number_prop)数据量较大的时候效率是很差的。(如果对于较小的表,不会造成显著地影响)


文中说到一种优化方式就是,手工将in里面的子查询查询出来,然后再拼装执行 ,这在程序中是可行的。


文中说到:但是总是认为子查询效率很差也是不对的,有时候可能子查询更好些。怎么确定这个事情呢,应该经过评测来决定(执行查询、用desc/explain等来看)。


在网上也能找到《高性能MySQL》的这节内容

参考资料4:MySQL 数据库优化(12)Limitations of the MySQL Query Optimizer
http://www.chenyajun.com/2009/01/03/1657




深入解析以太网接口中的BOB Smith电路设计 本文深入解析以太网接口中的BOB Smith电路设计,详细介绍了其在共模噪声抑制、浪涌防护和EMI优化中的关键作用。通过实际案例和设计要点,帮助工程师正确选择75Ω电阻和高压电容等元件,优化PCB布局,解决电压型与电流型PHY的设计差异,以及千兆与百兆以太网的特殊考量。 阅读详情

相关推荐

告别软件轮询!用STM32G474的COMP比较器实现纳秒级硬件过压保护(CubeMX配置详解)

本文详细介绍了如何利用STM32G474的COMP比较器实现纳秒级硬件过压保护,通过CubeMX配置详解,展示了硬件比较器相比传统软件轮询方案在响应时间、CPU占用和可靠性等方面的显著优势。文章还提供了实战配置流程和优化技巧,帮助工程师快速构建高效的硬件保护系统。

weixin_28683689的博客 351

sql的子查询超级慢-子查询酿的祸

今天碰到一个问题,就是子查询导致查询效率特别低,到了31秒了。特此先记录一下,后期修改。 前提条件:sz_jsxxb这个表是教师表,大约有5万多条数据 select sys_guid(), (select count(zgh)as nanrs from (select zgh,xydm from sz_jsxxb where xb='1') s where t.yxdm=s.xydm) ...

DAMO小天天 8548

国产化软件设计:遵循信创要求,助力信息技术自主创新

支持国产操作系统、CPU、数据库和中间件。确保网络通信的身份鉴别、数据传输机密性和完整性。实现应用和数据层的身份鉴别、数据传输机密性完整性、数据存储机密性完整性。依托法院密码服务平台提供的商用密码能力。

qq_41186565的博客 3371

oracle sql 语句嵌套子查询 查询速度慢

select        ----慢------------------         (select count(*)           from (select pe.personid, pe.pgd_sheetid           --------select * from WXU_NN_T_PG_PERSON t where t.flag != '4'  全表扫描  效

码灵的博客 8903

SAP ERP与金蝶云星空的集成案例(新能源光伏行业)

通过建设PLM、SAP、MES、WMS、SCADA、EAM等多系统集成的工业互联网平台作为数字化工厂的控制中枢,不仅可以实现人员、设备、物料、工艺参数、产品等生产全流程追溯管理,同时也可以根据数据采集进行生产现场的控制调节,最大程度降低能耗水平。销售订单创建下推金蝶采购订单创建修改、销售订单创建下推金蝶销售订单创建修改、销售发货过账下推金蝶采购入库单、销售发货过账下推金蝶销售出库单:在SAP ERP系统创建销售订单、销售发货过账单后推送到云星空系统,进行采购/销售订单的创建修改、完成物料的入库和出库流程。

集信通 1615

SRAM compiler选项中 Soft Error Repair (SER)

引起的瞬时故障,可能会影响 SRAM 中存储的数据。SER 功能通过某种机制检测并修复这些错误,从而提高存储器的可靠性。在 SRAM 编译器中,

hzmscut的博客 1153

mysql子查询导致查询变慢的一种优化思路

mysql子查询导致查询变慢的一种优化思路

romantic_angel的专栏 2337

手把手教你学Simulink——基于Simulink的机械臂正运动学仿真建模示例

机械臂正运动学概述正运动学的核心在于根据每个关节的角度值,通过坐标变换(如DH参数法或齐次变换矩阵)计算出末端执行器相对于基座的位置和姿态。常用的数学工具包括旋转矩阵、平移向量以及它们组合而成的齐次变换矩阵。仿真目标设计并实现一个机械臂正运动学模型。输入关节角度,输出末端执行器的位置和姿态。分析不同关节角度下的机械臂位置变化。假设我们有一个简单的3自由度(DOF)平面机械臂,其各关节的长度分别为l1l1​、l2l2​和l3l3​。在Simulink中,可以使用。

MHD0815的博客 359

关于Mysql子查询查询速度慢和索引失效的问题

这个语句没走索引,这里面的字段都是有索引的,后来强制 FORCE INDEX(id),还是不行,为什么呢,百度了一下,有两个知识点。sql优化:(将子查询转为链接查询就可以走索引啦)

a18372016358的博客 709

npm报错 npm WARN deprecated....的问题解决方式

报错 :npm WARN deprecated … 现象:无法进行有效的vue项目的部署以及npm install 命令的执行。 原因一:版本问题 说明:由于npm的版本过低或者过高导致的报错 检查版本: npm -v 如果版本是比较旧的,或者是最新的,这里可以进行对npm的更新和回退。 更新npm版本: npm updated -d 查看可以更新的版本 npm install -g npm 默认安装最新版本 安装回退指定的版本: npm updated -d 查看所有的版本 npm -g i.

任聪聪的博客 16万+

【YOLOv11工业级实战】22. YOLOv11动态蛇形卷积破解弯曲裂纹检测难题(附2小时部署代码)

摘要:本文聚焦工业场景中弯曲裂纹检测的核心痛点,针对风电叶片、织物纱线等曲线缺陷传统检测漏检率高的问题,提出基于动态蛇形卷积(DSC)的YOLOv11优化方案。因企业数据保密,采用AITEX织物缺陷库(含曲线纱线断裂标签)结合Blender物理仿真生成2000张弯曲裂纹数据,实现从数据准备到部署的全流程实操。通过将DSC模块插入YOLOv11 Neck层,弯曲裂纹召回率从68.1%提升至89.4%,mAP@0.5达83.7%,推理速度3.1ms(2080Ti)。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1153

多表查询

多表查询 概述 基础语法: select ​ 列名列表 from ​ 表名列表 where… 多表查询的分类 内连接查询: 隐式内查询: 使用where消除无用的数据 显式内查询 外链接查询: 子查询:

sjwl0526的博客 1823

使用OpenCV从低对比度图像中提取圆形轮廓

希望本文能帮助您从低对比度图像中提取圆形轮在本文中,我们将探讨如何使用OpenCV库从低对比度图像中提取圆形轮廓。低对比度图像通常指的是图像中的亮度差异很小,导致物体边缘不够清晰的情况。在本文中,我们将探讨如何使用OpenCV库从低对比度图像中提取圆形轮廓。低对比度图像通常指的是图像中的亮度差异很小,导致物体边缘不够清晰的情况。通过预处理图像并应用Hough变换,我们能够在低对比度图像中准确地提取圆形轮廓。通过预处理图像并应用Hough变换,我们能够在低对比度图像中准确地提取圆形轮廓。

ByteWhiz的博客 349

Mysql数据库插入查询优化小记。

前言,这几天工作做了个Mysql百万数据表在不同情况下比如子查询数量大小、模拟并发、主键-索引类型、连接方式(in、exists、join)的小测试。过程中无论模拟数据还是测试过程感觉都有很多可以改进的地方。这里记一下我在笔记本上的改进。(PS:工作时模拟了200W数据,开始后就忙别的了。忙完发现自己用的jdbc每条commit,单线程的方式跑的时间以小时记,幸亏没人看见,尴尬死了) 环境:I5...

赵俊杰 344

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Mysql exists用法小记

简介 EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False。 EXISTS 指定一个子查询,检测行的存在。语法:EXISTS subquery。参数 subquery 是一个受限的 SELECT 语句 (不允许有 COMPUTE 子句和 INTO 关键字)。结果类型为 Boolean,如果子查询包含行,则返回 TRUE。 示例 一张活动...

翎野君的博客 133

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Mysql优化小记

mysql优化小记

kerwin_F的博客 153

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

MySql

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34238642的博客 70

MySql折腾小记一:导数据出错,查询超慢

最近几天,把 秋色园QBlog放到Oracle上跑了一圈,修正了几个小bug之后,加了个别索引,运行情况良好。 接着把秋色园放到MySql上跑了一圈,发现问题不少,特此记录: 1:导数据,网上用了几个导数据的工具,不管用,最后用的Navicat for mysql 导数据,还是不管用。 几万的文章数据根据导不了: 一:字符集问题不匹配,导数据经常失败,最后改my.ini的字符类...

weixin_30793643的博客 62

mysql优化联表查询_[MySQL] MySQL联表查询的执行顺序优化查询

SELECT t4.orgName,t3.projectName,t3.Partner,t1.type,COUNT(DISTINCT t1.imei) AS countFROM `t_teminal` AS t1LEFT JOIN `t_orgcode_orgid_rela` AS t2ON t1.orgid = t2.orgIdLEFT JOIN `t_org_code` AS t3ON t2....

weixin_35998791的博客 289

帆软FineReport报表开发小记

摘要:FineReport是一款企业级低代码报表工具,支持报表制作、数据填报和数据可视化大屏,兼容主流数据库和多终端展示。其核心包括普通报表和决策报表两种模板,以及单元格扩展机制。开发流程涵盖需求梳理、数据准备、模板设计到测试发布等步骤。数据集分为服务器和模板数据集,SQL编写需遵循规范。报表开发涉及数据绑定、公式应用、参数面板控件、样式优化等,并提供图表、钻取、JS自定义等高级功能。性能优化需关注SQL、数据集、模板设计等方面。常见问题包括数据错乱、无数据等,需遵循命名、注释、复用等开发规范确保质量。

qq_43258077的博客 720

mysql执行sql语句优化分析命令explain命令小记

explain是用来分析sql语句,帮助优化的一个命令。她可以很详细的告诉你的sql语名出现的问题所在,以及是否用到索引。真的很好用。大家必须要会用哦! explain的语法如下:   SQL Code复制内容到剪贴板 explain [extended] select … from … where …   如果使用了extended,那么在执行完explain语句后

yongchao940的专栏 387

SQL调优小记

目录SQL优化SQL语句优化负向查询不能使用索引前导模糊查询不能使用索引数据区分不明显时,不应该建立索引字段的默认值不要为null在字段上进行计算不能命中索引最左前缀问题明确返回条数不要让数据库自动强制类型转换join时两表字段类型要相同小结SQL性能优化使用Explain进行SQL分析优化数据访问量重构查询方法当存在慢SQL时,我们首先需要检测一下SQL语句是否可以进行优化(写SQL的时候就需要思考能否优化),然后,再考虑性能优化。当我们使用not in的时候,哪怕中了索引, 也是相当于失效的。 前导

Stray_Lambs的博客 721

每周小记——SpringBoot&Mybatis-Plus

本文概述SpringBoot实践及整合MyBatis-Plus与Swagger,涵盖基础配置(环境搭建、YAML、多环境部署、热部署),框架整合(Swagger3自动API文档、MyBatis-Plus简化CRUD/逻辑删除/乐观锁/代码生成器/多数据源),高级特性(YAML封装、函数式接口、ActiveRecord模式),实用技巧(自定义Banner、分页/自定义SQL、枚举处理、Service封装),以代码示例驱动企业级开发。

weixin_57655687的博客 2390

MySQL数据库内存表的特性与使用介绍

内存表,就是放在内存中的表,所使用内存的大小可通过My.cnf中的max_heap_table_size指定,如max_heap_table_size=1024M,内存表与临时表并不相同,临时表也是存放在内存中,临时表最大所需内存需要通过tmp_table_size = 128M设定。当数据超过临时表的最大值设定时,自动转为磁盘表,此时因需要进行IO操作,性能会大大下降,而内...

weixin_34099526的博客 202

《MySql学习》 Select 查询语句慢的非性能原因

因为,SQL语句在执行前,都会打开相应的表对象,如select * from t1语句,会找到t1表的frm文件,并打开表内存对象。为了控制表对象使用的内存空间和其他资源,MySQL会隐式(后台表对象管理线程)或显式(flush tables等)来关闭已打开但并没有使用的表对象。然而,正在使用的表对象是不能关闭的(如SQL请求仍在运行),因此,Flush Tables操作会被正在运行的SQL请求阻塞。但是 id : 86 是我们的查询语句,想找出是哪个会话ID造成的查询语句堵塞,还得使用下面的语句。

纸上得来终觉浅,绝知此事要躬行 3601

Mysql子查询导致查询变慢的一种优化思路

将子查询的数据先查询出来保存到一个临时中间表(中间表也建立了索引),然后再关联查询,速度提升是很明显的!这类子查询,会直接导致表格索引失效,当数据量到达一定规模后,查询就会特别慢,甚至是超时。如果SQL特别复杂,无法直接关联,那可以试下这种新的思路,一种优化思路是,直接使用表格关联,去掉子查询。我之前使用的SQL子查询,1分钟都不出来结果。使用中间表,查询不超过2秒!

可小辉的博客 786
上一篇: 在CentOS下安装crontab服务
下一篇: 强烈推荐:Vim实战手册
codingstandards
博客等级 码龄16年 12粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值