标签:alter 执行 老师 优先 返回 磁盘 ack 使用 HERE
例子:select city,name,age from t where city=‘杭州‘ order by name limit 1000 ;
查询流程如下:
图中“按 name 排序”这个动作,可能在内存中完成,也可能需要使用外部排序,这取决于排序所需的内存和参数 sort_buffer_size。sort_buffer_size,就是 MySQL 为排序开辟的内存(sort_buffer)的大小。如果要排序的数据量小于 sort_buffer_size,排序就在内存中完成。但如果排序数据量太大,内存放不下,则不得不利用磁盘临时文件辅助排序。
要点:
1、MySQL会为每个线程分配一个内存(sort_buffer)用于排序该内存大小为sort_buffer_size
2、如果排序的数据量小于sort_buffer_size,排序将会在内存中完成
3、如果排序数据量很大,sort_buffer_size内存中无法存下这么多数据,则会使用磁盘临时文件来辅助排序,也称外部排序
4、在使用外部排序时,MySQL会分成好几份单独的临时文件用来存放排序后的数据,然后在将这些文件合并成一个大文件
缺点:
1.造成sort_buffer中存放不下很多数据,因为除了排序字段还存放其他字段,对sort_buffer的利用效率不高
2.当所需排序数据量很大时,会有很多的临时文件,排序性能也会很差
优点:MySQL认为内存足够大时会优先选择全字段排序,因为这种方式比rowid 排序避免了一次回表操作
通过控制排序的行数据的长度来让sort_buffer中尽可能多的存放数据,但是如果 MySQL 认为排序的单行长度太大超过max_length_for_sort_data设置的长度就会采用另一种算法
执行流程如下
rowid 排序多访问了一次表 t 的主键索引
最后的“结果集”是一个逻辑概念,实际上 MySQL 服务端从排序后的 sort_buffer 中依次取出 id,然后到原表查到 city、name 和 age 这三个字段的结果,不需要在服务端再耗费内存存储结果,是直接返回给客户端的
优点:更好的利用内存的sort_buffer进行排序操作,尽量减少对磁盘的访问
缺点:回表的操作是随机IO,会造成大量的随机读,不一定就比全字段排序减少对磁盘的访问
其实,并不是所有的 order by 语句,都需要排序操作的。从上面分析的执行过程,MySQL 之所以需要生成临时表,并且在临时表上做排序操作,其原因是原来的数据都是无序的,那如果能够保证从 city 这个索引上取出来的行,天然就是按照 name 递增排序的话,是不是就可以不用再排序了呢?
创建一个 city 和 name 的联合索引,对应的 SQL 语句是:alter table t add index city_user(city, name);
在这个索引里面,可以用树搜索的方式定位到第一个满足 city=‘杭州’的记录,并且额外确保了,接下来按顺序取“下一条记录”的遍历过程中,只要 city 的值是杭州,name 的值就一定是有序的。
执行流程如下:
这个语句的执行流程有没有可能进一步简化呢?
针对这个查询,可以创建一个 city、name 和 age 的联合索引,对应的 SQL 语句就是:alter table t add index city_user_age(city, name, age);
查询流程图:
问题:1)无条件查询如果只有order by create_time,即便create_time上有索引,也不会使用到。
因为优化器认为走二级索引再去回表成本比全表扫描排序更高。
所以选择走全表扫描,然后根据老师讲的两种方式选择一种来排序
2)无条件查询但是是order by create_time limit m.如果m值较小,是可以走索引的.
因为优化器认为根据索引有序性去回表查数据,然后得到m条数据,就可以终止循环,那么成本比全表扫描小,则选择走二级索引。
即便没有二级索引,mysql针对order by limit也做了优化,采用堆排序
标签:alter 执行 老师 优先 返回 磁盘 ack 使用 HERE
原文地址:https://www.cnblogs.com/zzq919/p/14430385.html