深入MySQL(四):MySQL的SQL查询语句性能优化概述 (2)

EXPLAIN待会再解释,大家只要知道该关键字可以看到大致扫描行数即可。
可以看到扫描行数为1行,返回的行数也是一行。
我们删除掉‘test’索引,再来执行同样的语句:

mysql> EXPLAIN SELECT * from user where account = 12345; +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+ | 1 | SIMPLE | user | NULL | ALL | NULL | NULL | NULL | NULL | 991536 | 10.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)

可以看到,我们的扫描行数非常大,是一个全表扫描,但是我们返回的行数其实是一行,也就是说我们做了大量的无用扫描。
一般MySQL能够使用如下三种方式应用WHERE条件,从好到坏依次为:

在索引中使用WHERE条件过滤不匹配的记录。这是在存储引擎完成的。

使用覆盖索引扫描返回记录,直接从索引中过滤不需要的记录并返回命中的结果。MySQL的服务层完成的,不需要回表。

从数据表中返回数据,然后过滤不满足条件的记录。在MySQL服务器层完成。

重构查询的方式

常见的重构查询的方式有以下几种:

将一个复杂查询拆分为多个简单查询

切分查询,对大查询分而治之,一次查询一小部分结果

分解关联查询

一个复杂查询还是多个简单查询

在传统的实现中,强调在数据库层完成尽可能多的工作,在过去是认为网络通信、查询解析和优化是一件代价很高的事情。
但是MySQL的设计让连接和断开连接都十分轻量级,返回一个小的查询结果方面很高效。MySQL内部每秒能够扫描内存中上百万行数据,相较而言,MySQL响应数据给客户端速度很慢。
所以有的时候可以权衡一下是否需要将一个大查询分解为多个小查询。

切分查询

有时候对于一个大查询分而治之,将一个大查询分解为小查询。每个查询功能完全一样,每次只返回一小部分。
最典型的场景便是删除旧数据,比如要删除100w旧数据,如果一次SQL执行全部删除,那么该SQL语句会执行相当长的过程,同时可能导致锁住大量数据、占满整个事务日志、耗尽系统资源、阻塞其他查询。那么我们可以一次删除1w的旧数据,这样子就可以将删除全部旧数据的性能损耗平摊到一个很长的时间,大大降低对于服务器的影响。

分解关联查询

关于JOIN关键字,很多DBA会直接禁用JOIN语句,原因是JOIN语句可能会扫描大量的行数,在后期的博客中,我会专门总结。简单而言,如果被驱动表上面不能使用索引,那么会直接每次查询被驱动表的时候都进行全表扫描,A JOIN B的扫描行数会直接是A的行数 * B的行数
所以我们可以将一个JOIN语句拆分成多个简单的查询,然后在应用程序中进行组装。

分解关联查询可以有以下优点:

执行单个查询可以减少锁的竞争

应用层做关联,更容易对数据库进行拆分,更容易做到高性能和可扩展

可以减少冗余记录的查询

这种形式相当于在应用层做了哈希关联,很多情况下哈希关联效率高很多

MySQL优化器

MySQL的优化器是一个基于成本的优化器,有些原因会导致MySQL优化器选择错误的执行计划:

统计信息不准确。

执行计划的成本估计并不等于实际成本。

MySQL的最优并不只是考虑响应时间。

MySQL不考虑并发执行的情况。

MySQL有时候会基于一些固定规则优化。

MySQL能够处理的优化类型有以下:

重新定义关联表的顺序

将外连接转为内连接

使用等价变化规则:比如合并和减少一些比较、移除一些恒等或者不恒等的判断,例如(5=5 AND a>5)会被改写为a>5。

优化COUNT()、MIN()、MAX()

预估并转化为常数表达式

覆盖索引扫描

子查询优化

提前终止查询:LIMIT、发现一个不成立的条件。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzffjd.html