1.切片查询
将大查询切分成小查询,删除旧的数据就是一个很好的例子。定期清除大量数据时,如果用一个大的语句一次性完成的话,则可能需要一次锁住很多数据、占满整个事务日志、耗尽系统资源、阻塞很多小的但重要的查询。
2.分解联接查询
很多高性能的应用都会对联接查询进行分解。简单地说,可以对每一个表进行一次单表查询,然后将结果在应用程序中进行联接。例如,下面这个查询:
优点:
1)多次查询利用缓存
2)可以有序IO读取数据
3)单个查询减少锁竞争
4)减少冗余记录访问
3.查询执行的基础
1. 客户端给服务器发送一条SQL查询语句。
2. 服务器端进行SQL语句解析、预处理,再由优化器生成对应的执行计划。
3. MySQL根据优化器生成的执行计划,调用存储引擎的API来执行查询。
4. 将结果返回给客户端。
4.查询优化器
有很多种原因会导致MySQL优化器选择错误的执行计划,如下所示:
● 统计信息不准确。MySQL服务器依赖存储引擎提供的统计信息来评估成本,但是有的存储引擎提供的信息是准确的,有的偏差可能非常大。例如,InnoDB因为其MVCC的架构,并不能维护一个数据表的行数的精确统计信息。
● 成本指标并不完全等同于运行查询的实际成本,因此即使统计数据是准确的,查询的成本也可能超过或者低于MySQL估算的近似值。例如,有时候某个执行计划虽然需要读取更多的页面,但是它的成本却更低。因为如果这些页面都是顺序读或者这些页面都已经在内存中的话,那么它的访问成本将很低。MySQL并不知道哪些页面在内存中、哪些在磁盘中,所以查询在实际执行过程中到底需要多少次物理I/O是无法得知的。
● MySQL的最优可能和你想的最优不一样。你可能希望执行时间尽可能短,但是MySQL只是基于其成本模型选择最优的执行计划,而有些时候这并不是最快的执行方式。所以,这里我们看到的根据执行成本来选择执行计划并不是完美的模型。
● MySQL从不考虑其他并发执行的查询,这可能会影响到当前查询的速度。
● MySQL也并不是任何时候都是基于成本的优化。它有时也会基于一些固定的规则,例如,如果存在全文搜索的MATCH()子句,则在存在FULLTEXT索引的时候就使用全文索引。即使有时候使用其他索引和WHERE条件可以远比这种方式要快,MySQL也仍然会使用对应的全文索引。
● MySQL不会考虑不受其控制的操作的成本,例如,执行存储函数或者用户自定义函数的成本。
● 后面我们还会看到,优化器有时候无法估算所有可能的执行计划,所以它可能错过实际上最优的执行计划
在很多数据库服务器中,IN()完全等同于多个OR条件的子句,因为这两者是完全等价的。在MySQL中这点是不成立的,MySQL将IN()列表中的数据先进行排序,然后通过二分查找的方式来确定列表中的值是否满足条件,这是一个O(logn)复杂度的操作,等价地转换成OR查询的复杂度为O(n),对于IN()列表中有大量取值的时候,MySQL的处理速度将会更快。
表和索引的统计信息
MySQL架构由多个层次组成。在服务器层有查询优化器,却没有保存数据和索引的统计信息。统计信息由存储引擎实现
MySQL如何执行联接查询
我们先来看一个UNION查询的例子。对于UNION查询,MySQL先将一系列的单个查询结果放到一个临时表中,然后再重新读出临时表中的数据来完成UNION查询。在MySQL的概念中,每个查询都是一次联接,所以读取临时表的结果也是一次联接。
在MySQL 8.0.20版本之后,已经不再使用基于块的嵌套循环联接操作,取而代之的是哈希联接(参见链接33)。
执行计划
MySQL生成查询的一棵指令树[10],然后通过查询执行引擎执行完成这棵指令树并返回结果。最终的执行计划包含了重构查询的全部信息。如果你对某个查询执行EXPLAIN EXTENDED后,再执行SHOW WARNINGS,就可以看到重构出的查询。[11]
多表联接的一种方式
被称为一棵平衡树。但是,这并不是MySQL执行查询的方式。正如我们在前面章节中介绍的,MySQL总是从一个表开始,一直嵌套循环、回溯完成所有表联接。所以,MySQL的执行计划总是如图8-3所示,是一棵左侧深度优先的树。
MySQL如何实现多表联接
联接查询优化器通过评估不同顺序时的成本来选择一个成本最低的联接顺序。
这和我们前面给出的执行计划完全不同。MySQL从actor表开始(从上面的EXPLAIN结果的第一行输出可以看出这一点),然后与我们前面的计划按照相反的顺序进行联接。这样是否效率更高呢?我们来看看。我们先使用STRAIGHT_JOIN关键字,按照之前的顺序执行,下面是对应的EXPLAIN输出结果:
排序优化
无论如何排序都是一个成本很高的操作,所以从性能角度考虑,应尽可能避免排序或者尽可能避免对大量数据进行排序。
当不能使用索引生成排序结果的时候,MySQL需要自己进行排序,如果数据量小则在内存中进行,如果数据量大则需要使用磁盘,不过MySQL将这个过程统一称为文件排序(filesort),即使完全是在内存中排序不需要任何磁盘文件时也是如此。
如果需要排序的数据量小于“排序缓冲区”,MySQL使用内存进行快速排序操作。如果内存不够排序,那么MySQL会先将数据分块,对每个独立的块使用“快速排序”进行排序,并将各个块的排序结果存放在磁盘上,然后将各个排好序的块进行合并(merge),最后返回排序结果。
MySQL有如下两种排序算法。
两次传输排序(旧版本使用)
读取行指针和需要排序的字段,对其进行排序,然后再根据排序结果读取所需要的数据行。
这需要进行两次数据传输,即需要从数据表中读取两次数据,第二次读取数据的时候,因为是读取排序列进行排序后的所有记录,这会产生大量的随机I/O,所以两次传输排序的成本非常高。
单次传输排序(新版本使用)
先读取查询所需要的所有列,然后再根据给定列进行排序,最后直接返回排序结果。
因为不再需要从数据表中读取两次数据,对于I/O密集型的应用来说,这样做的效率高了很多。另外,相比两次传输排序,这个算法只需要一次顺序I/O就可读取所有的数据,而无须任何的随机I/O。然而,这种方式可能占用更多空间,因为会保存查询中每一行所需要的列,而不仅仅是进行排序操作所需要的列。这意味着更少的元组可以放入排序缓冲区,使得文件排序(filesort)操作必须执行更多的排序合并过程。
查询执行引擎
在解析和优化阶段,MySQL将生成查询对应的执行计划,MySQL的查询执行引擎会根据这个执行计划来完成整个查询。这里的执行计划是一个数据结构,而不是和很多其他的关系数据库那样生成对应的可执行的字节码。
将结果返回给客户端
MySQL将结果集返回客户端是一个增量且逐步返回的过程。
服务器端无须存储太多的结果,也就不会因为要返回太多结果而消耗太多内存。另外,这样的处理也可让MySQL客户端第一时间获得返回的结果。[12]结果集中的每一行都会以一个满足MySQL客户端/服务器通信协议的封包发送,再通过TCP协议进行传输,在TCP传输的过程中,可能对MySQL的封包进行缓存,然后批量传输。
标签:联接,结果,查询,排序,MySQL,执行,优化 From: https://www.cnblogs.com/cuinima/p/17024436.html