04、05年做项目的时候,用SQL Server 2000,核心表(大部分使用频繁的关键功能每次都要用到)达到了800万数据量,很早以前查过一些相关表,有的达到了3000多万,磁盘使用的光纤盘,100G空间,每周必须备份转移数据,否则100G空间一周会满掉,这个系统几年来,目前仍然保持非常良好的性能。还听说过朋友的SQL Server 2000数据库工作在几十TB的环境下,高并发量,对这种级别的驾驭能力我还是差的很遥远。
数据库中,象tableA inner join tableB、tableA left out join tableB这样的SQL语句是如何执行join操作的?就是说SQL Server使用什么算法实现两个表数据的join操作?
sql Server 2000有三种方式:nested loop、merge、hash。Oracle也是使用这三种方式,不过Oracle选择使用nested loop的条件跟SQL Server有点差别,内存管理机制跟SQL Server不一样,因此查看执行计划,Oracle中nested loop运用非常多,而merge和hash方式相对较少,SQL Server中,merge跟hash方式则是非常普遍。
以SQL Server 2000为例对这三种方式进行说明,穿插在里面讲解执行计划的一些初级使用。
1. nested loop join
1.1 示例SQL
select ... from tableA inner join tableB on tableA.col1=tableB.col1 where tableA.col2=? and tableB.col2=?tableA中没有建立任何索引,tableB中在col1上有建立一个主键(聚集索引)。
1.2 算法伪代码描述
foreach rowA in tableA where tableA.col2=?{search rowsB from tableB where tableB.col1=rowA.col1 and tableB.col2=? ;if(rowsB.Count<=0)discard rowA ;elseoutput rowA and rowsB ;}
前面三个执行步骤a)、b)、c)跟1.4中一样,有一点需要注意的是,步骤c)是执行Index Seek操作,它跟Clustered Index Seek有区别。聚集索引的根节点是每一条实际数据记录,而非聚集索引的根节点是对聚集索引根结点键值的引用(如果表存在聚集索引),或者是对实际数据记录rowid的引用(指没有聚集索引的表,这种表称为heap表)。Clustered Index Seek执行之后,实际的物理数据记录已经被加载到内存中,而Index Seek操作之后,并没有加载实际的物理数据记录,而只是非聚集索引的根结点数据,其中只包含了索引字段数据以及引用的聚集索引键值或者rowid。SQL Server在这个步骤中使用非聚集索引根结点数据中的索引字段值,与outer input中的记录(rowA)关联字段进行匹配,判断是否是符合条件的结果,如果是,则将非聚集索引根结点数据结构保存到nested loop操作的输出数据结构中,并且会创建一个书签(Bookmark),指示在必要的时候需要根据这个书签去获取引用的数据。