System R 作为第一个关系数据库系统实现了Codd的关系模型。虽然已经有30年了。但基本的思路和今天的实现仍然一样。下面我们来沿着于1979年发表的”Access Path Selection in a Relational Database Management System” 来看一下世上第一个实现版本。
对于一个SQL语句 Select … From … Where … , System R 分为四步来处理:
Parsing, Optimization, Code Generation, Execution
我们关注第一和第二步。Parsing 用来解析SQL statement,解析的结果包括了一个包含select中的项的list,一个包含from中表的list, 一个用来表达where中布尔逻辑的树。Optimization就是重点部分了。
回到我们提出的三个基本问题:
1. 如何快速有效地找到一个集合包含了low cost 的plan. 如果我们在query中有n个布尔操作苻。所有的排列将会有n!种。显然我们无法使用包含所有的plan的集合。我们需要一种方法快速选出那些可能是最快的plan
2. 如何准确地评估cost. 一个例子是如果我们应该使join发生在尽量小的两个表中。也就是说我们应该先在大表中选出一个子集再join. 而不是
3. 如何在集合中进行搜索
System R是怎么处理的呢?
对于1:
这个问题System R并没提出一个方案。它只是使用了所有的排列可能。估计当初系统设计中,也没有几个表。
对于2:
简单而言,System R的作者给出了一个公式:
Cost=page fetched+w*(Storage Engine Call)
Page fetched实际反映了从硬盘读数据的I/O操作。. Storage Engine Call 反映了CPU(包括内存操作)比如遍历和查找。但在实际中如何估计呢。System R采用的方式是对每一个操作如索引scan, 正常的scan以及join操作给出一个分数。 这个分数于所要操作的表和字段有关。
首先,System R保存了对于数据库的统计信息。 这些信息在表和索引建立的时候更新。平时则是定时更新。保存的统计信息包括:
对于每个表T:
1. NCARD(T) 表中的元素个数 (cardinality of relation)
2. TCARD(T) 表的页数。
3. P(T) 表的页数占总页数的比例
对于在表T上的每个索引I:
1. 索引中的key
2. 索引所占的page
(待续)