Mysql 中的排序实现

本文主要是记录本人对mysql中关于结果集合排序的代码的阅读。

由于马上要为公司的sqlproxy产品添加分表功能,对于被分的大表的查询需要在sqlproxy中进行merge,如果查询的语句有order by的话,还需要进行排序。 所以想起看下mysql中是如何进行结果集排序的。

1. 概述
mysql内部执行一条语句大体上分为3个步骤,prepare, optimize和exec。 (可以到sql/sql_select.cc中查看)

prepare 做些初始化的工作:分配下内存,处理下别名,字段等等。。。
optimize 做些优化: 优化下查询条件,计算最优执行计划,根据逻辑简化一些查询操作,还有很多。。。。
exec 就是具体执行语句了。

接下来看看关于order by 排序, 这3步中都做了什么。

2. order by 在 prepare
在prepare中,关于order by主要的工作就是解析出 order by条件对应的字段.
如果order by后面接的是个不大于select字段列表长度的数值,那么就表明oder by的字段已经在select list中了。如果order by后面跟的是字符串的话,它会根据需要遍历查询语句的select中列出的字段列表,所查询的表的所有字段,还有就是外查询中的字段和表。然后把解析出来的字段添加到select字段列表的最前面。具体代码参考:
入口: setup_without_group (sql/sql_base.cc :578) 和setup_order (sql/sql_base.cc :21061)
具体的实现:
sql/sql_select.cc的20906行的find_order_in_list和 sql/sql_base.cc :6806行的 find_item_in_list。

然后是做一些简单的处理,主要是把不需要排序的情况给排除,如:
1. 长度为0的not null字段上排序
2. 长度为0的函数上排序
3. 返回的结果集大小为0或1
具体代码参考: sql/sql_select.cc 的613行。

3. order by 在 optimize
在optimize中,关于order by的工作主要是
1. 去除order by中的常量,并且判断是否order by只包含简单的表达式(order by字段从head table中取,并且这个table不是一个left join的表)。 这将决定在排序的时候是否必须使用临时表。
参考代码: remove_const(sql/sql_select.cc :2067)
2. 如果order by后面只有NULL或常量,忽略order by (sql/sql_select.cc :2079)
3. 如果oder by依赖的字段不再第一个表中(查询语句的),那么需要使用中间临时表(sql/sql_select.cc:2275)
4. 把之前优化时去掉的常量条件添加上,以避免file_sort时进行全表扫描。(不太懂。。。sql/sql_select.cc:2425)
5. 决定是否使用临时表(sql_select:2448)
6. 如果order by在第一个表,那么先进行排序,使用create_sort_index 。(sql_select:2579)
......

4. order by 在exec
在exec中,关于order by的主要工作是:
排序。
代码入口是sql_select.cc的3193行
真正的排序是从 create_sort_index( sql_select.cc的20316行)开始的。

主要的逻辑就是判断order by的字段是否是索引,如果是的话,使用该索引进行查询并跳过排序(索引必须包含所有order by字段,见代码test_if_skip_sort_order   sql_select.cc:19948);否则使用filesort。

在filesort中如果结果集合可以全部装入内存的话 (save_index    sql/filesort.cc:285):
1. 使用基数+计数排序 (mysys/mf_radix.c:28),如果结果集合大于1000行小于10万行并且排序字段少于20个。
(关于基数排序:http://baike.baidu.com/view/1170573.htm;
关于计数排序: http://zh.wikipedia.org/wiki/计数排序)
2. 使用快速排序 (mysys/mf_qsort.c:94)

否则的话,就要使用临时文件进行merge(merge_buffers  filesort.cc:1408行)。这里看得不是很懂,已经看懂的是它通过插入排序的方式将临时文件中的内容读入内存进行排序。
根据filesort算法的解释,应该是先将所有临时文件中的排序,然后分别读取各个临时文件的第一个,把最大或最小的输出,再补齐,再比较,再输出,再补齐。。。。。。

5. 后记
代码看得比较粗略,看多少先记多少,后面慢慢细揪。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值