❤️ 个人主页:水滴技术
订阅专栏:高性能 MySQL
支持水滴:点赞 + 收藏⭐ + 留言
高性能 MySQL(一):逻辑架构
高性能 MySQL(二):并发控制(锁)
高性能 MySQL(三):事务与锁详解
高性能 MySQL(四):多版本并发控制(MVCC)
高性能 MySQL(五):设计表结构时,如何选择数据类型会更高效?
高性能 MySQL(六):索引类型
高性能 MySQL(七):11个高性能的索引策略
高性能 MySQL(八):通过优化数据访问,来解决慢查询
大家好,我是水滴~~
上一篇我们讲到通到优化数据访问,来解决慢查询问题,这是解决慢查询的基础。但有时我们的查询过于复杂,导致查询速度慢,我们不得不重构查询。今天就来讲下重构查询的几种方式。
重构查询时,有一个比较好的技巧是:将一个复杂的查询,分解成多个简单的查询。
在传统的实现中,总是想让数据库层完成尽可能多的工作,即通过一次查询得出想要的结果,这会让我们的查询变得复杂。之所有这样想逻辑,一般是认网络通信、查询解析和优化是一件代价很高的事情。
但是这样的想法对于 MySQL 并不适用,MySQL 从设计上让连接和断开连接都很轻量级,在返回一个小的查询结果方面很高效。
MySQL 内部每秒能够扫描内存中上百万行数据,相比之下,MySQL 响应数据给客户端就慢得多了。在条件相同的情况下,越少的查询性能就越好。所以将一个大查询分解为多个小查询是很有必要的。
有时候对于一个大查询我们需要“分而治之”,将大查询切分成小查询,每个小查询的功能完全一样,只完成一小部分,每次只返回一小部分查询结果。
批量删除旧的数据就是一个很好的例子。在定期清除大量数据时,如果用一个大的语句一次性完成的话,则可能需要一次锁住很多数据、占满整个事务日志、耗尽系统资源、阻塞很多小的但重要的查询。可以将一个大的delete
语句切分成多个较小的语句,可以尽可能小地影响 MySQL 的性能,同时还能减少 MySQL 复制的延迟。
很多高性能的应用都会对关联查询进行分解。即对每一个表进行一次单表查询,然后将结果在应用程序中进行关联。
例如,下面语句是查出“软件工程2101班”的所有学生:
SELECT
s.*
FROM
class c
JOIN class_student_rel cs ON c.id= cs.class_id
JOIN student s ON s.id = cs.student_id
WHERE
c.name= '软件工程2101班';
可以将该关联查询分解成两个单表查询:
select id from class where name= '软件工程2101班';
select student_id from class_student_rel where class_id = 1;
select * from student where id in (1, 2, 3, 4, 5, 6);
为什么要这样做呢?乍一看,这样做并没有什么好处,本来是一条查询,这里却需要变成多条查询,返回的结果又是一模一样的。
事实上,分解关联查询有如下优势:
class
已经被缓存了,那么应用程序就可以路过第一个查询。in()
代替关联查询,可以让 MySQL 按照 ID
顺序进行查询,这比随机的关联更高效。