一、常用查询连接算法演示
简单介绍选择操作和连接操作的实际算法,确切地说是算法思想。每一种操作有多种执行这个操作的算法。
选择操作的实现
如下实现算法:
例:Select * from student where <条件表达式>;
考虑<条件表达式>的几种情况:
C1:无条件;
C2:Sno='200215121';
C3:Sage>20;
C4:Sdept='CS'AND Sage>20;
1.简单的全表扫描方法
对查询的基本表顺序扫描,注意检查每个元组是否满足选择条件,把满足条件的元组作为结果输出。对于小表,这种方法简单有效。对于大表顺序扫描十分费时,效率很低。
2.索引(或散列)扫描方法
如果选择条件中的属性上有索引(例如B+树索引或Hash索引,可以用索引扫描方法。通过索引先找到满足条件的元组主码或元组指针,再通过元组指针直接在查询的基本表中找到元组。
例-C2:以C2为例,Sno='200215121',并且Sno上有索引(或Sno是散列码),则可以使用索引(或散列)得到Sno为'200215121'元组的指针,然后通过元组指针在student表中检索到该学生。
例-C3:以C3为例,Sage>20,并且Sage上有B+树索引,则可以使用B+树索引找到Sage=20的索引项,以此为入口点在B+树的顺序集上得到Sage>20的所有元组指针,然后通过这些元组指针到student表中检索到所有年龄大于20的学生。
例-C4:以C4为例,Sdept='CS' AND Sage>20,如果Sdept和Sage上都有索引,一种算法是;分别用上面两种方法分别找到Sdept='CS'的一组元组指针和Sage>20的另一组元组指针,求这2组指针的交集,再到student表中检索,就得到计算机系年龄大于20的学生。
另一种算法是找到Sdept='CS'的一组元组指针,通过这些元组指针到student表中检索,并对得到的元组检索另一些选择条件(如Sage>20)是否满足,把满足条件的元组作为结果输出。
二:连接操作的实现
连接操作室查询处理中最耗时的操作之一。不失一般性,这里只讨论等值连接(或自然连接)最常用的实现算法.
[例]SELECT * FROM Student,SC WHERE Student.Sno=SC.Sno;
1.嵌套循环方法(nested loop)
这是最简单可行的算法。对外层循环(Student)的每一个元组(s),检索内层循环(SC)中的每一个元组(sc),并检查这两个元组在连接属性(sno)上是否相等。如果满足连接条件,则串接后作为结果输出,直到外层循环表中的元组处理完为止。
2.排序-合并方法(sort-merge join或merge join)
这也是常用的算法,尤其适合连接的诸表已经排好序的情况。
用排序-合并连接方法的步骤是:
(1)如果连接的表没有排好序,首先对Student表和SC表按连接属性Sno排序;
(2)取Student表中第一个Sno,依次扫描SC表中具有相同Sno的元组;把他们连接起来(如图9,2所示);
(3)当扫描到Sno不相同的第一个SC元组时,返回Student表扫描它的下一个元组,再扫描SC表中具有相同的Sno的元组,把它们连接起来。
重复上述步骤直到Student表扫描完。
这样Studetn表和SC表只要扫描一遍。当然,如果2个表原来无序,执行时间要加上对两个表的排序时间。即使这样,对于2个大表,先排序后使用sort-merge join方法执行连接,总的时间一般仍会大大减少。
3、索引连接(index join)方法
用索引连接方法的步骤是:
(1)在SC表上建立属性Sno的缩影,如果原来没有的话;
(2)对Student中每一元组,由Sno值通过SC的索引查找相应的SC元组;
(3)把这些SC元组和Student元组连接起来。
循环执行(2)(3),直到Student表中的元组处理完为止。
4、Hash Join方法
把连接属性作为hash码,用同一个hash函数把R和S中的元组散列到同一个hash文件中。第一步,划分阶段(partitioning phase),对包含较少元组的表(比如R)进行一遍处理,把它的元组按hash函数分散到hash表的桶中;第二步,试探阶段(probing phase),也称为连接阶段(join phase),对另一个表(S)进行一遍处理,把S的元组散列到适当的hash桶中,并把元组与桶中所有来自R并与之相匹配的元组连接起来。
上面hash join算法假设两个表中较小的表的第一阶段后可以完全放入内存的hash桶中。不需要这个前提条件的hash join算法以及许多改进的算法就不说了。以上的算法思想可以推广到更加一般的多个表的连接算法上。