数据库原理:MySQL文件排序算法与参数

对于不能利用索引避免排序的SQL,数据库不得不自己实现排序功能以满足用户需求,此时SQL的执行计划中会出现“Using filesort”,
这里需要注意的是filesort并不意味着就是文件排序,其实也有可能是内存排序,这个主要由sort_buffer_size参数与结果集大小确定。

假设表结构和SQL语句如下:
CREATE TABLE t1 (
id INT,
col1 VARCHAR (64),
col2 VARCHAR (64),
col3 VARCHAR (64),
PRIMARY KEY (id),
KEY (col1, col2)
);
SELECT col1,col2,col3 FROM t1 WHERE col1>100 ORDER BY col2;

a.常规排序,双路排序
(1).从表t1中获取满足WHERE条件的记录
(2).对于每条记录,将记录的主键+排序键(id,col2)取出放入sort buffer
(3).如果sort buffer可以存放所有满足条件的(id,col2)对,则进行排序;否则sort buffer满后,进行排序并写到临时文件中。(排序算
法采用的是快速排序算法)
(4).若排序中产生了临时文件,需要利用归并排序算法,保证临时文件中记录是有序的
(5).循环执行上述过程,直到所有满足条件的记录全部参与排序
(6).扫描排好序的(id,col2)对,即sort buffer,并利用主键id去取SELECT需要返回的其他列(col1,col2,col3)
(7).将获取的结果集返回给用户。

从上述流程来看,是否使用文件排序主要看sort buffer是否能容下需要排序的(id,col2)的结果集,这个buffer的大小由
sort_buffer_size参数控制。此外一次排序还需要两次IO,一次是取排序字段(id,col2)到sort buffer中,第二次是通过上面取出的主键
id再来取其他所需要返回列(col1,col2,col3),由于返回的结果集是按col2排序,因此id是乱序的,通过乱序的id取(col1,col2,col3)时
会产生大量的随机IO。对于第二次IO取MySQL本身会优化,即在取之前先将主键id排序,并放入缓存区,这个缓存区大小由参数
read_rnd_buffer_size控制,然后有序去取记录,将随机IO转为顺序IO。

b.优化排序,单路排序
常规排序方式除了排序本身,还需要额外两次IO。优化排序方式相对于常规排序,减少了第二次IO。主要区别在于,一次性取出SQL中出现
的所有字段放入sort buffer中而不是只取排序需要的字段(id,col2)。由于sort buffer中包含了查询需要的所有字段,因此排序完成后可
以直接返回,无需二次取数据。这种方式的代价在于,同样大小的sort buffer,能存放的(col1,col2,col3)数目要小于(id,col2),如果
sort buffer不够大,可能导致需要写临时文件,造成额外的IO。当然MySQL提供了参数max_length_for_sort_data,只有当排序SQL里出现
的所有字段小于max_length_for_sort_data时,才能利用优化排序方式,否则只能用常规排序方式。



猜你喜欢

转载自blog.51cto.com/13598811/2335463