MySQL Order By索引优化
在一些情况下,MySQL可以直接使用索引来满足一个ORDER BY 或GROUP BY 子句而无需做额外的排序。尽管ORDER BY 不是和索引的顺序准确匹配,索引还是可以被用到,只要不用的索引部分和所有的额外的ORDER BY 字段在WHERE 子句中都被包括了。
使用索引的MySQL Order By
下列的几个查询都会使用索引来解决ORDER BY 或GROUP BY 部分:
SELECT * FROM t1 ORDER BY key_part1,key_part2,... ;
SELECT * FROM t1 WHERE key_part1=constant ORDER BY key_part2;
SELECT * FROM t1 WHERE key_part1=constant GROUP BY key_part2;
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 DESC;
SELECT * FROM t1 WHERE key_part1=1 ORDER BY key_part1 DESC, key_part2 DESC;
不使用索引的MySQL Order By
在另一些情况下,MySQL无法使用索引来满足ORDER BY,尽管它会使用索引来找到记录来匹配WHERE 子句。这些情况如下:
* 对不同的索引键做ORDER BY :
SELECT * FROM t1 ORDER BY key1, key2;
* 在非连续的索引键部分上做ORDER BY:
SELECT * FROM t1 WHERE key2=constant ORDER BY key_part2;
* 同时使用了ASC 和DESC:
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC;
* 用于搜索记录的索引键和做ORDER BY 的不是同一个:
SELECT * FROM t1 WHERE key2=constant ORDER BY key1;
* 有很多表一起做连接,而且读取的记录中在ORDER BY 中的字段都不全是来自第一个非常数的表中(也就是说,在EXPLAIN 分析的结果中的第一个表的连接类型不是const)。
* 使用了不同的ORDER BY 和GROUP BY 表达式。
* 表索引中的记录不是按序存储。例如,HASH 和HEAP 表就是这样。
通过执行EXPLAIN SELECT ... ORDER BY,就知道MySQL是否在查询中使用了索引。如果Extra 字段的值是Using filesort,则说明MySQL无法使用索引。详情请看"7.2.1 EXPLAIN Syntax (Get Information About a SELECT)"。当必须对结果进行排序时,MySQL 4.1以前 它使用了以下filesort 算法:
1. 根据索引键读取记录,或者扫描数据表。那些无法匹配WHERE 分句的记录都会被略过。
2. 在缓冲中每条记录都用一个‘对’存储了2个值(索引键及记录指针)。缓冲的大小依据系统变量sort_buffer_size 的值而定。
3. 当缓冲慢了时,就运行qsort(快速排序)并将结果存储在临时文件中。将存储的块指针保存起来(如果所有的‘对’值都能保存在缓冲中,就无需创建临时文件了)。
4. 执行上面的操作,直到所有的记录都读取出来了。
5. 做一次多重合并,将多达MERGEBUFF(7)个区域的块保存在另一个临时文件中。重复这个操作,直到所有在第一个文件的块都放到第二个文件了。
6. 重复以上操作,直到剩余的块数量小于MERGEBUFF2 (15)。
7. 在最后一次多重合并时,只有记录的指针(排序索引键的最后部分)写到结果文件中去。
8. 通过读取结果文件中的记录指针来按序读取记录。想要优化这个操作,MySQL将记录指针读取放到一个大的块里,并且使用它来按序读取记录,将记录放到缓冲中。缓冲的大小由系统变量read_rnd_buffer_size 的值而定。这个步骤的代码在源文件`sql/records.cc' 中。
这个逼近算法的一个问题是,数据库读取了2次记录:一次是估算WHERE 分句时,第二次是排序时。尽管第一次都成功读取记录了(例如,做了一次全表扫描),第二次是随机的读取(索引键已经排好序了,但是记录并没有)。在MySQL 4.1 及更新版本中,filesort 优化算法用于记录中不只包括索引键值和记录的位置,还包括查询中要求的字段。这么做避免了需要2次读取记录。改进的filesort 算法做法大致如下:
相关新闻>>
- 发表评论
-
- 最新评论 更多>>