欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 会展 > MySQL · 性能优化 · 提高查询效率的实用指南(上)

MySQL · 性能优化 · 提高查询效率的实用指南(上)

2024/11/5 16:56:04 来源:https://blog.csdn.net/u012263509/article/details/141949737  浏览:    关键词:MySQL · 性能优化 · 提高查询效率的实用指南(上)

前言

在过去的几年里,MySQL作为一款开源数据库,因其稳定性和性能得到了广泛的应用。始终保持着强劲的增长趋势,越来越多的企业和开发者将其作为首选数据库,甚至有部分企业从Oracle迁移至MySQL。然而,随着使用的普及,MySQL在实际应用中也暴露出了一些常见问题,尤其是当SQL语句不够优化时,可能会导致响应时间慢、CPU使用率高等性能瓶颈问题。

请在此添加图片描述

今天我总结了常见的SQL错误用法,供大家参考:

LIMIT 语句

错误用法: 在应用程序中,分页查询是非常常见的操作场景。然而,LIMIT语句在数据量较大的情况下容易出现性能问题。

SELECT*
FROMoperation
WHEREtype = 'SQLStats'
AND NAME = 'SlowLog'
ORDER BYcreate_time
LIMIT 1000, 10;

LIMIT参数较小时,例如LIMIT 1000, 10,查询性能尚可,但当参数变为LIMIT 1000000,10时,即使程序员仅需提取10条记录,查询时间依然可能显著增加。原因在于数据库必须从头开始扫描并计算每一行,直到达到所需的记录位置。

优化方案: 为了避免这种性能问题,可以通过重新设计SQL语句,将上一页的最大值作为查询条件。

SELECT*
FROMoperation
WHEREtype = 'SQLStats'
AND NAME = 'SlowLog'
AND create_time > '2017-03-16 14:00:00'
ORDER BYcreate_time
LIMIT 10;

这种方式确保了查询时间基本固定,不会随着数据量的增长而变化。

原理解析: MySQL在执行LIMIT查询时,必须遍历满足条件的所有记录,直到到达指定的偏移量。因此,随着LIMIT偏移量的增加,查询的时间复杂度线性增加。通过将上一页的最大值作为查询条件,可以避免数据库扫描大量无关记录,从而大幅提高查询效率。


隐式转换

错误用法: SQL语句中字段类型与查询变量类型不匹配是另一个常见错误。

EXPLAIN EXTENDED SELECT*
FROMmy_balance b
WHEREb.bpn = 14000000123
AND b.isverified IS NULL;

在上述语句中,bpn字段定义为varchar(20),而查询条件中的14000000123是一个整数。MySQL会自动将字符串转换为数字再进行比较,这会导致索引失效,进而影响查询性能。

优化方案: 为避免隐式转换,应确保查询变量与字段类型一致。例如,可以将查询条件中的整数转换为字符串形式:

SELECT*
FROMmy_balance b
WHEREb.bpn = '14000000123'
AND b.isverified IS NULL;

原理解析: 当MySQL遇到类型不匹配的情况时,会尝试进行隐式转换,以确保语句能够执行。然而,这种转换通常会导致索引失效,因为索引的原始数据类型与转换后的数据类型不匹配。因此,查询效率会大幅下降。通过确保查询条件与字段类型一致,可以避免不必要的转换操作,从而提升查询效率。


关联更新、删除

错误用法: 虽然MySQL 5.6引入了物化特性来优化查询性能,但对于更新或删除操作,仍需手工重写为JOIN,以提高执行效率。例如,以下UPDATE语句的执行方式为循环嵌套子查询(DEPENDENT SUBQUERY):

UPDATE operation o
SET STATUS = 'applying'
WHEREo.id IN (SELECTidFROM(SELECTo.id,o. STATUSFROMoperation oWHEREo. GROUP = 123AND o. STATUS NOT IN ('done')ORDER BYo.parent,o.idLIMIT 1) t);

优化方案: 通过将子查询改写为JOIN,可以显著提高更新语句的执行速度:

UPDATE operation o
JOIN (SELECTo.id,o. STATUSFROMoperation oWHEREo. GROUP = 123AND o. STATUS NOT IN ('done')ORDER BYo.parent,o.idLIMIT 1
) t ON o.id = t.id
SET STATUS = 'applying';

原理解析: MySQL在处理嵌套子查询时,需要为每一行执行子查询,这通常会导致性能问题。而JOIN操作通过在一张表中查找匹配的行,避免了多次子查询的执行,从而显著提升性能。


混合排序

错误用法: MySQL通常无法利用索引进行混合排序,但在某些场景下可以通过特殊的重写方式提高性能。

以下查询语句执行计划显示为全表扫描:

SELECT*
FROMmy_order o
INNER JOIN my_appraise a ON a.orderid = o.id
ORDER BYa.is_reply ASC,a.appraise_time DESC
LIMIT 0, 20;

优化方案: 可以将查询拆分为两个部分并合并结果,从而提高查询效率:

SELECT*
FROM((SELECT*FROMmy_order oINNER JOIN my_appraise a ON a.orderid = o.idWHEREis_reply = 0ORDER BYappraise_time DESCLIMIT 0,20)UNION ALL(SELECT*FROMmy_order oINNER JOIN my_appraise a ON a.orderid = o.idWHEREis_reply = 1ORDER BYappraise_time DESCLIMIT 0,20)) t
ORDER BYis_reply ASC,appraise_time DESC
LIMIT 20;

原理解析: MySQL在混合排序的情况下,通常需要对整个数据集进行排序,这会导致较高的计算成本。通过将查询拆分为多个部分,再合并结果,可以减少MySQL在排序过程中的负担,进而提高查询速度。


EXISTS语句

错误用法: MySQL在处理EXISTS子句时,仍然采用嵌套子查询的执行方式,这会导致性能问题。

SELECT*
FROMmy_neighbor n
LEFT JOIN my_neighbor_apply sra ON n.id = sra.neighbor_id
AND sra.user_id = 'xxx'
WHEREn.topic_status < 4
AND EXISTS (SELECT1FROMmessage_info mWHEREn.id = m.neighbor_idAND m.inuser = 'xxx'
)
AND n.topic_type <> 5;

优化方案: 可以通过将EXISTS子查询改写为JOIN来提高查询效率:

SELECT*
FROMmy_neighbor n
INNER JOIN message_info m ON n.id = m.neighbor_id
AND m.inuser = 'xxx'
LEFT JOIN my_neighbor_apply sra ON n.id = sra.neighbor_id
AND sra.user_id = 'xxx'
WHEREn.topic_status < 4
AND n.topic_type <> 5;

原理解析: MySQL在执行EXISTS子查询时,会为主查询的每一行执行一次子查询,导致性能问题。通过将EXISTS改写为JOIN,可以避免不必要的重复查询,从而显著提高执行效率。

总结

数据库编译器负责生成执行计划,这一计划将决定SQL语句的实际执行方式。然而,编译器仅仅是尽力而为,因为所有数据库的编译器都并非完美无缺。许多性能问题在其他数据库系统中也同样存在。唯有深入了解数据库编译器的特性,我们才能规避其不足之处,从而编写出高性能的SQL语句。

因此,在设计数据模型和编写SQL语句时,程序员需要将算法的思想或意识融入其中。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com