2008年(239)
分类:
2008-06-17 23:47:19
系统对SQL语句的处理可能需要进行排序。这主要是由于以下两个原因引起的:
(1)在SQL语句中,指定要对结果集进行排序,或者包含需要排序的关键字。
(2)进行表连接时,系统选用排序归并连接、散列连接;或者系统虽然选用嵌套循环连接,但发现作为输入的表如果已排序,其实现效率会更高。有关表连接的详细信息,可参见第5.3.2一节。
如果在要排序的字段上存在索引,系统就直接使用该索引,顺序读取表,从而完成排序。如果在要排序的字段上不存在索引,或者尽管存在索引,但按照索引访问需要更多的系统开销时,系统就不会使用索引,只是在最后,基于此字段对结果集进行排序。
如果要排序的数据,可以一次在内存中完成,这种排序就称为内排序。如果由于内存空间限制,无法一次完成数据的排序,系统就按照可用内存的空间大小,将要排序数据分成多个部分、分别排序,中间结果被存放在磁盘上,最后将多个已排序结果集合并,形成最终的结果集,这种排序称为外排序。
很显然,内排序的执行效率很高。如果数据库中存在排序操作,我们当然希望所有的排序均能够一次在内存中完成。
在SQL语句中出现下列的关键字后,如果优化器没有选用相关的索引,就一定会进行排序操作。
1. order by
该关键字要求对结果集进行排序。如果表中的某些字段经常在order by中使用,在这些字段上建立索引将有助于避免数据库中的排序操作。
2. group by
该关键字要求对结果集进行分组。系统对分组的处理,是首先基于要分组的字段进行排序,然后对已排序的记录数据,从上到下采取以下的处理步骤,形成结果集:
(1)取出第一条记录,放入结果集。
(2)取出下一条记录。如果该条记录和结果集中最后一条记录在要分组字段上取值相等,就将该条记录和最后一条记录合并;如果不相等,就将该记录放在结果集的最后面。
(3)继续处理,直到所有的记录被处理完成。
例如,下面SQL语句返回各部门中员工的月工资总额:
SELECT dept_no, sum(empy_salary)
FROM employee group by dept_no
系统首先对员工表employee基于部门号dept_no进行排序。然后对已经排序的记录集,按照字段dept_no的值,将字段empy_salary中的值相加。
3. distinct
该关键字要求结果集中不能有重复的记录。系统对distinct的处理,类似于对group by的处理。系统首先按照结果集中要求的字段进行排序,然后按照以下步骤剔除重复的记录。
(1)取出第一条记录,放入结果集。
(2)取出下一条记录。如果该条记录和结果集中最后一条记录相同,就放弃该条记录;如果不相同,就将该记录放在结果集的最后面。
(3)继续处理,直到所有的记录被处理完成。
例如,下面SQL语句从员工表employee中返回所有的部门号:
SELECT distinct dept_no
FROM employee
系统首先读取表employee中的所有记录,基于字段dept_no进行排序。然后对已经排序的记录集,按照字段dept_no的值,删除重复的记录。
4. 集合操作:union、intersect、minus
集合操作:union、intersect、minus,用来实现了两个记录集之间的并、交、差运算,其中:
(1)union:合并两个记录集,结果集中不能有重复的记录。
(2)intersect:返回同时出现在两个记录集中的记录。
(3)minus:返回出现在第一个记录集,而不在第二个记录集的所有记录。
对于这些集合运算,系统首先将两个记录集基于相同的字段或者字段组合,分别按照相同的方向排序,然后将这两个已经排序的记录集合从上到下进行比较,从而找到最终的结果集。
这里,我们需要注意关键字union和union all的区别。union all允许结果集中有重复的记录,因此优化器不会要求对记录集进行排序。