【MySQL从入门到精通】【高级篇】(二十八)子查询优化,排序优化,GROUP BY优化和分页查询优化

本文涉及的产品
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
简介: 上一篇文章我们介绍了 1024程序员节|【MySQL从入门到精通】【高级篇】(二十七)外连接和内连接如何进行查询优化呢?join的原理了解一波,这篇文章我们接着来学习,本文主要学习的是子查询优化,排序优化,GROUP BY优化以及分页查询优化。

1. 简介


上一篇文章我们介绍了 1024程序员节|【MySQL从入门到精通】【高级篇】(二十七)外连接和内连接如何进行查询优化呢?join的原理了解一波,这篇文章我们接着来学习,本文主要学习的是子查询优化,排序优化,GROUP BY优化以及分页查询优化。

测试数据

1.测试表 student表中有50万条数据

2.测试表 class表中有1万条数据

1.子查询优化

MySQL从4.1版本开始支持子查询,使用子查询可以进行SELECT 语句的嵌套查询,即一个SELECT 查询的结果作为另一个SELECT 语句的条件。子查询可以一次性完成很多逻辑上需要多个步骤才能完成的SQL操作。

子查询是MySQL的一项重要的功能,可以帮助我们通过一个SQL语句实现比较复杂的查询。但是,子查询的执行效率不高。 原因:


执行子查询时,MySQL需要为内层查询语句的查询结果建立一个临时表,然后外层查询语句从临时表中查询记录。查询完毕后,再撤销这些临时表。这样会消耗过多的CPU和IO资源,产生大量的慢查询。

子查询的结果集存储在临时表,不论是内存临时表还是磁盘临时表都不会存在索引,所以查询性能会受到一定的影响。

对于返回结果集比较大的子查询,其对查询性能的影响也就越大。

在MySQL中,可以使用连接(JOIN)查询来替代子查询。 连接查询不需要建立临时表,其速度比子查询要快,如果查询中使用索引的话,性能就会更好。

举例1:查询学生表中是班长的学生信息

使用子查询

-- 查询学生表中是班长的学生信息
CREATE INDEX idx_monitor ON class(monitor);
-- 使用子查询
EXPLAIN SELECT * FROM student stu1 WHERE stu1.stuno IN(SELECT monitor FROM class c WHERE

这里可以看出使用使用子查询的耗时是 。0.33秒。

接下来看下使用多表关联查询

-- 使用多表关联查询
EXPLAIN SELECT stu1.* FROM student stu1 JOIN class c ON c.monitor IS NOT NULL AND stu1.

可以看出使用多表关联查询的比子查询要耗时,两个表的索引情况如下,在student表中的stuno字段没有添加索引,所以关联的时候会比较耗时。

给student表的stuno字段添加索引

CREATE INDEX idex_stuno ON student(stuno);

下面就给student表中的stuno字段添加索引再看下效果。两者的速度都比较快

如果子查询的表数据比较少,子查询的结果比较少的话可以使用子查询。否则可以考虑使用多表关联,但是关联的字段必须要建立索引,比如关联查询效果比子查询还要差。

举例2:取所有不为班长的同学

SELECT SQL_NO_CACHE * FROM student stu1 WHERE stu1.stuno NOT IN(SELECT monitor FROM class c WHERE monitor IS NOT NULL);

可以看出使用关联查询的效果非常差,查询时间高达2.086s。

SELECT SQL_NO_CACHE stu1.* FROM student stu1 LEFT JOIN class c ON  stu1.stuno=c.monitor AND c.monitor IS NULL ;

使用关联查询则好一点。

2. 排序优化

问题:在WHERE条件字段上加索引,但是为什么在ORDER BY字段上还要加索引呢?

回答:在MySQL中,支持两种排序方式,分别为FileSort和Index排序。

Index排序中,索引可以保证数据的有序性,不需要再进行排序,效率更高。

FileSort排序则一般在内存中进行排序,占用CPU比较多,如果待排结果较大,会产生临时文件I/O到磁盘进行排序的情况,效率较低。

过程一:删除两个表的索引,写一个普通的排序查询

ALTER TABLE student DROP INDEX idex_stuno;
ALTER TABLE class DROP INDEX   idx_monitor;
-- 过程一
EXPLAIN SELECT SQL_NO_CACHE * FROM student ORDER BY age,classId;

可以看出没有索引的情况下,排序使用的是 filesort 排序,也就是在内存中排序。

过程二,创建索引,order by时不limit,索引失效

下面在student表中创建idx_age_classid_name索引。

CREATE INDEX idx_age_classid_name ON student(age,classId,`name`);
EXPLAIN SELECT SQL_NO_CACHE * FROM student ORDER BY age,classId;

可以看出使用的排序方式还是 filesort的方式,也就以为着索引失效了。

增加limit过滤条件,使用上索引了。

EXPLAIN SELECT SQL_NO_CACHE * FROM student ORDER BY age,classId LIMIT 1000;

过程三:ORDER BY时顺序错误,索引失效

EXPLAIN SELECT SQL_NO_CACHE * FROM student ORDER BY age DESC,classId LIMIT 1000;

过程五:无过滤,不索引

SHOW INDEX FROM student;
# 索引有效
EXPLAIN SELECT * FROM student WHERE age=45 ORDER BY classId;
#索引有效
EXPLAIN SELECT * FROM student WHERE age=45 ORDER BY classId LIMIT 10;
# 索引无效
EXPLAIN SELECT * FROM student WHERE classId=45 ORDER BY classId LIMIT 10;

优化建议:

SQL中,可以在WHERE子句和ORDER BY子句中使用索引,目的是WHERE子句中避免全表扫描,在ORDER BY子句避免使用FileSort排序。,当然,某些情况下全表扫描,或者FileSort排序不一定比索引慢。但总的来说,我们还是要避免,以提高查询效率。

尽量使用Index完成ORDER BY排序。如果WHERE和ORDER BY 后面是相同的列就使用单索引列;如果不同就使用联合索引。

无法使用Index时,需要对FileSort方式进行调优。

小结

INDEX a_b_c(a,b,c)
ORDER BY 能使用索引最左前缀
- ORDER BY a
- ORDER BY a,b
- ORDER BY a,b,c
- ORDER BY a DESC,b DESC,c DESC
如果WHERE使用索引的最左前缀定义为常量,则order by能使用索引
- WHERE a=const ORDER BY b,c
- WHERE a=const AND b=const ORDER BY c
- WHERE a=const ORDER BY b,c
- WHERE a=const AND b>const ORDER BY b,c
不能使用索引进行排序
-ORDER BY a ASC,b DESC,c DESC  /*排序不一致*/
- WHERE b=const ORDER b,c /*丢失a索引*/
- WHERE a=const ORDER BY c /*丢失b索引*/
- WHERE a=const ORDER BY a,d /*d不是索引的一部分*/
- WHERE a in (...) ORDER BY b,c /*对于排序来说,多个相等条件也是范围查询*/

排序优化实战

ORDER BY子句,尽量使用index方式,避免使用FileSort方式排序。

执行案例前先清除student上的索引,只留主键:

场景:查询年龄为30岁的,且学生编号小于101000的学生,按用户名称排序

EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age=30 AND stuno<101000 ORDER BY NAME;

结论:type是ALL,即最坏的情况,Extra里出现了Using filesort也是最坏的情况,优化是必须的。

优化思路:

方案一:为了去掉filesort我们可以把索引建成如下这样:

CREATE INDEX idx_age_name ON student(age,`name`);
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age=30 AND stuno<101000 ORDER BY NAM

这样就优化掉了using filesort。

3. GROUP BY优化

group by 使用索引的原则几乎跟order by一致,group by即使没有过滤条件用到索引,也可以直接使用索引。

group by先排序在分组,遵照索引建的最佳左前缀法则

当无法使用索引列,增大max_length_for_sort_data 和sort_buffer_size 参数的设置

where效率高于having,能写在where限定的条件就不要写在having中了

减少使用order by,和业务沟通能不排序就不排序,或者将排序放在程序端去做,order by、group by、distinct这些语句较为耗费CPU,数据库的CPU资源极其宝贵。

包含了order by、group by、distinct这些查询的语句,where条件过滤出来的结果集请保存在1000行以内,否则SQL会很慢。

4. 优化分页查询

一般分页查询时,通过创建覆盖索引能够比较好地提高性能。一个常见又非常头疼的问题就是limit 200000,10,此时需要MySQL排序前200010记录,仅仅返回200000~200010 的记录,其他记录丢弃,查询排序的代价非常大。

EXPLAIN SELECT * FROM student LIMIT 200000,10;

这里全表扫描,共计扫描了499086条数据。

优化思路一:

在索引上完成排序分页操作,最后根据主键关联回原表查询所需要的其他列内容。

EXPLAIN SELECT * FROM student t,(SELECT id FROM student ORDER BY id LIMIT 200000,10) t1
WHERE t.id=t1.id;

优化思路二:

该方案适用于自增的表,可以将limit查询转换成某个位置的查询。

EXPLAIN SELECT * FROM student WHERE id>200000 LIMIT 10;


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
6月前
|
缓存 关系型数据库 MySQL
降低MySQL高CPU使用率的优化策略。
通过上述方法不断地迭代改进,在实际操作中需要根据具体场景做出相对合理判断。每一步改进都需谨慎评估其变动可能导致其他方面问题,在做任何变动前建议先在测试环境验证其效果后再部署到生产环境中去。
280 6
|
7月前
|
存储 SQL 关系型数据库
MySQL 核心知识与索引优化全解析
本文系统梳理了 MySQL 的核心知识与索引优化策略。在基础概念部分,阐述了 char 与 varchar 在存储方式和性能上的差异,以及事务的 ACID 特性、并发事务问题及对应的隔离级别(MySQL 默认 REPEATABLE READ)。 索引基础部分,详解了 InnoDB 默认的 B+tree 索引结构(多路平衡树、叶子节点存数据、双向链表支持区间查询),区分了聚簇索引(数据与索引共存,唯一)和二级索引(数据与索引分离,多个),解释了回表查询的概念及优化方法,并分析了 B+tree 作为索引结构的优势(树高低、效率稳、支持区间查询)。 索引优化部分,列出了索引创建的六大原则
186 2
|
7月前
|
存储 SQL 关系型数据库
MySQL 动态分区管理:自动化与优化实践
本文介绍了如何利用 MySQL 的存储过程与事件调度器实现动态分区管理,自动化应对数据增长,提升查询性能与数据管理效率,并详细解析了分区创建、冲突避免及实际应用中的关键注意事项。
334 0
|
5月前
|
缓存 关系型数据库 BI
使用MYSQL Report分析数据库性能(下)
使用MYSQL Report分析数据库性能
450 158
|
5月前
|
关系型数据库 MySQL 数据库
自建数据库如何迁移至RDS MySQL实例
数据库迁移是一项复杂且耗时的工程,需考虑数据安全、完整性及业务中断影响。使用阿里云数据传输服务DTS,可快速、平滑完成迁移任务,将应用停机时间降至分钟级。您还可通过全量备份自建数据库并恢复至RDS MySQL实例,实现间接迁移上云。
|
5月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS费用价格:MySQL、SQL Server、PostgreSQL和MariaDB引擎收费标准
阿里云RDS数据库支持MySQL、SQL Server、PostgreSQL、MariaDB,多种引擎优惠上线!MySQL倚天版88元/年,SQL Server 2核4G仅299元/年,PostgreSQL 227元/年起。高可用、可弹性伸缩,安全稳定。详情见官网活动页。
1059 152
|
5月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS支持MySQL、SQL Server、PostgreSQL和MariaDB引擎
阿里云数据库RDS支持MySQL、SQL Server、PostgreSQL和MariaDB引擎,提供高性价比、稳定安全的云数据库服务,适用于多种行业与业务场景。
825 156
|
5月前
|
缓存 监控 关系型数据库
使用MYSQL Report分析数据库性能(中)
使用MYSQL Report分析数据库性能
438 156
|
5月前
|
缓存 监控 关系型数据库
使用MYSQL Report分析数据库性能(上)
最终建议:当前系统是完美的读密集型负载模型,优化重点应放在减少行读取量和提高数据定位效率。通过索引优化、分区策略和内存缓存,预期可降低30%的CPU负载,同时保持100%的缓冲池命中率。建议每百万次查询后刷新统计信息以持续优化
536 161
|
6月前
|
存储 运维 关系型数据库
从MySQL到云数据库,数据库迁移真的有必要吗?
本文探讨了企业在业务增长背景下,是否应从 MySQL 迁移至云数据库的决策问题。分析了 MySQL 的优势与瓶颈,对比了云数据库在存储计算分离、自动化运维、多负载支持等方面的优势,并提出判断迁移必要性的五个关键问题及实施路径,帮助企业理性决策并落地迁移方案。

推荐镜像

更多