第六章 类属B树索引技术 对基于树的索引方法给出一种通用算法。该算法是建立在类属B树的概念之上开发的。它将类型系统开放,使系统能支持用户自定义的数据类型、函数和某些特殊的查询谓词的集合。并且,将新的数据类型、函数、查询谓词等登记到数据库管理系统中,
SQL-92把每个表的列属性限制为如下数据类型之一: ▼整数 ▼浮点数 ▼字符串(定长或可变长) ▼日期、时间和区间 ▼数值和小数 另外,SQL-92定义了一系列精确的(及硬编码的)函数和操作符。这些函数和操作符可用于各种数据类型。
SQL的数据类型和操作的集合非常有限 证券市场的日历问题: 考虑下面的一张经过简化的表,它是一张财政单据的一部分, 用于存放证券单据: create table bonds( name varchar(30), 证券的名称 rate float, 所付的利率 date_bought date, 买入日期 date_sold date, 卖出日期 interest float); 收到的利息
计算利息域 用户也许想用下面的SQL命令来运行: update bond set interest = rate*(date_sold - date_bought) 来计算利息域。
传统的DBMS日期数据类型的确切语义是公历日期,因为该类型上所有的SQL操作符都使用公历。 但是,并不是所有的证券市场都使用公历,比如美国的证券市场均不使用公历。 证券持有者每月从同一张财政证券上获得的利息是相同的,不管这个月有多长。也就是说,同一张证券每个月的红利恒定而不随该月天数的多少而变化。 这样,关于日期相减的定义应该符合证券业实际使用的日历。用这种日历,3月15日减去2月15日总是30天。每年由12个等长的月组成,每个月都是30天。
用户自定义数据类型的原理 一个数据类型定义,为若干个对象和在这些对象上执行的各种操作的集合体。不论程序处理的是系统预定义的数据类型还是用户定义的数据类型,都必须考虑到对象和操作这两个方面。 对于对象的说明,以及在对象之上所执行操作的说明,分离于对象的表达以及操作的实现。
一个数据类型的实现对于程序的其它部分是不可见的。尤其是,程序的其他部分不能直接访问该数据类型的内部表示。系统仅通过一定的操作来控制该数据类型,而这些操作是该数据类型特有的。另外,一个数据类型内部实现的变化将不会影响到程序的其余部分,只要该数据类型仍提供同样的操作功能。唯一需要作改变的地方是直接访问数据类型内部表达的操作代码部分。
数据类型定义借助C++中的class机制 不同于Pascal和C,C++明确地提供了一种机制,即“类”(class)。用来将说明和实现进行区分,以及将一个抽象数据类型的实现对它的用户进行隐蔽。
类型存储信息的定义 SQL-92中的数据类型有硬编码的输入、输出函数,在该类型的ASCII表示和磁盘表示之间进行转换。实质上,每个类型都有ASCII表示和一种内部存储表示。 可扩充类型系统不用硬编码例程对内部和外部形式进行转化,而是由新类型的定义者指定要用的转换例程。这些转换例程对数据如何管理灵活性很大。输入和输出例程有可能什么也不做。在这种情况下,内部和外部表示是一样的。但也有可能转换例程执行任意的转换。 对象关系系统中,数据类型是作为特定的一类信息的存储表示以及对该类信息适用的操作符和函数来定义的。也就是说,数据类型既是信息又是操作。相反,关系系统中的域则仅包含存储表示而没有和域相关的行为。
比较谓词的定义 对用户定义的类型,用户必须能加入类型所要求的比较操作符,因为只有在新定义的数据类型上定义了完备的比较操作符,系统才能够用类属索引技术对其进行索引检索。
操作函数的定义 比如,某公司有一个查询,它要求找到以某个雇员的家庭所在地为圆心,半径为1公里的圆形区域内的该公司的所有雇员,那么这个查询可以用ORSQL表示如下: select r.name from emp,emp r where emp.name=’Jane’ and Distance(emp.location,r.location)<1; 显然,如果用户定义了“location”为“点”这个数据类型,并用它来表示雇员的家庭所在地的话,那么,要想使这个查询能顺利地执行,还必须在点这个类型上定义Distance这个操作函数。
类属的B树 目的: 我们实现类属B树模块(Generalized B-Tree, 记为GBT), 试图使得ORDBMS的存取操作能在任何数据类型之上进行。
定义: GBT可看作是m-路查找树的特例。它也是一种平衡树。 GBT存储一对 (关键字Ki,记录标识RID) 树的内结点存储一对 (关键字Ki,子页指针Ai)
特点: (1) GBT带有三个参数:KT, Less_Than, LessOrEqual。 此处,KT表示关键字的数据类型;
(2) 它最多有m棵子树,其根具有如下结构: (A0, K1,A1, K2,A2, ……,Kn,An) 其中:Ai (0 i n m)是指向子树的子页指针, Ki(1 i n m)是关键字。 且Ki的数据类型为KT。
在子树A0中的所有关键字值的集合{К0}满足: {К0}LessOrEqual K1 在子树Am 中的所有关键字值的集合{Кm}满足: (3) 如果一个结点N的所有关键字有序的排列成 K1,K2, ……, Km, 则N的子树也存在一个有序的排列 A0, A1, A2, ……,Am,且 在子树A0中的所有关键字值的集合{К0}满足: {К0}LessOrEqual K1 在子树Am 中的所有关键字值的集合{Кm}满足: Km-1 Less_Than {Кm} 在子树Ai (0i<n)中的所有关键字值的集合{Кi}满足: Ki-1 LessOrEqual {Кi} Less_Than Ki+1。 (4)子树仍然是一个GBT树。
GBT中,关键字Ki 的数据类型并不像B树中的那样单一。它可以是用户定义的任一种数据类型。 另外, 比较谓词less_Than 、LessOrEqual 并不只是代表传统的B树中所具有的比较谓词 “<” 、 “≤” 。 而是具有更广泛的含义。
要使得GBT能正确地在用户定义的数据类型之上进行操作,我们必须让GBT知道这个新数据类型所具有的物理含义: 用户需定义新数据类型的表示法 定义与之相应的比较谓词(与新数据类型相匹配的比较操作函数模块)。 书写它的操作函数。
实例: 地理数据类型 分析: 一个GIS系统需要存储三维空间中的对象。这些对象可以是点或其它任何形状。它的数据元素是二维或三维的。它可以用来描述房屋,道路,桥梁,管道和其它地物。通过对这些处理对象的分析与归纳, 我们抽象出下面四种数据模型作为开发GIS应用系统所需使用的数据类型。
点模型POINT POINT(name,x,y,z,parameter); 曲线模型CURVE CURVE(name,P1,P2,…,Pn,parameter); 面模型AREA AREA(name, P1,P2,…,Pn, P1,parameter);
体模型VOLUME 对 一个空间实体,需表示出其三维表面特征,我们将这种对象定义为体模型VOLUME;我们用有向的三角平面集合来定义其外表面 VOLUME{ name,A1,A2,…,An} 这里Ai, i=1,2,…,n为有向的空间三角平面。其数据类型为AREA,
其数据结构可用点-面表来实现。 点表: Pi x y z P1 0 0 1 P2 1 0 1 P3 1 0 0 P4 0 0 0 P5 0 1 1 P6 1 1 1 P7 1 1 0 P8 0 1 0 面表: Ai Pm Pn Pk A1 P1 P4 P3 A2 P1 P3 P2 A3 P2 P3 P6 .. .. .. ..
比较谓词的定义 由于GBT树中,结点关键字Ki的数据类型是可变化的,这就导致比较谓词必须随着关键字类型的变化而变化。 即如果GBT模块中,关键字的数据类型KT是用户自定义的, 则GBT模块中使用的比较谓词Less_Than和LessOrEqual也必须相应的使用用户自定义的比较谓词。
我们编写出比较谓词函数模块North_of如下: 当使用GBT进行操作时,如果索引关键字的数据类型KT为POINT类型时,则GBT模块中的形式参数Less_Than用North_of函数来置换。 我们编写出比较谓词函数模块North_of如下: Boolean Function North_of(point_1, point_2: POINT) /* two parameters that have data types POINT*/ { if (point_1.x > point_2.x) then return (true) else return (false) }
同样可编写比较操作函数模块Shorter_than如下: Boolean Function Shorter_than(line_1, line_2: CURVE) { a = length(line_1); b = length(line_2); if a < b then return(true) else return(false) } Float Function length(L:CURVE) N = L.n; /*to obtain the vertex number of the curve*/ sum = 0; for i = 1 to N-1 sum = sum + distance(pi+1 – pi); return(sum);
类型构造器
类型存储信息的定义 当用户要求定义新的数据类型时,启动类型构造器,屏幕上首先显示出定义类型存储信息的窗口。该窗口要求用户输入:类型名,类型结构,及比较谓词函数名等
相应于“<”和 “<=”的比较谓词函数名“North_of”和NorthOrSame”。 函数代码的定义在另外窗口中定义
使用同样的过程定义出一个名为CURVE的新类型
地理信息系统的查询,需要一些带有空间、时间特性的查询: 查询操作函数 地理信息系统的查询,需要一些带有空间、时间特性的查询: 1.部分匹配查询。为一维或多维指定一些数值,并且查找与这些值匹配的所有点。 2.范围查询。给出一维或多维的范围,并且要求查找出落在该范围内的所有的点。或者如果给出若干个多边形,问是否着个多边型的集合部分或全部落在这个区域内。这个查询推广了我们在第五章中讨论的一维范围索引。
3.最近邻居查询。寻找一个与给定点最邻近的点。例如:如果用点描述城市,我们可能想找到一个与一个已经给定的小城市最邻近的超过十万人口的城市。 4.“我在哪”查询. 给出一个点,想知道它被确定在哪一个多边形里,或者说定位这个点。一个很熟悉的例子就是当你点击鼠标时,系统判断你正在击哪一个已显示出来的元素。
为POINT类型引入二个查询操作函数Contained 和Above Boolean Function ABOVE(s1, s2) /* to retrieve the objects S1 that are located above of the objects S2. The data type of S1 and S2 (POINT, CURVE, AREA, VOLUME). And S1,S2 flat files f.*/ <Processing algorithm> parse ORSQL and interpret it to operation-lines; interpret header of files f. while there are more entities s in the file begin next E(f,s); if test E(f,s) s1 then E(f,s) -> T1; if test E(f,s) s2 then E(f,s) -> T2; end
while there are more entities s1 in T1 begin next E(T1,s1); if test E(T1,s1) is up of E(T2,s2) then insert E(T1,s1) into the out-line; end To explain and put out the output-lines.
Boolean Function CONTAINED(s1, s2) /* to retrieve the objects, S1, which are located inside of another object S2. The data type of S1 and S2 (POINT, CURVE, AREA, VOLUME). And S1,S2 flat files f. */ <processing algorithm> parse ORSQL and interpret it to operation-lines; interpret header of files f; while there are more entities in f; begin next E(f, S1); if E(f, S1) E(f, S2) then insert E(f, S1) to the out-line; end. To explain and put out the output-lines.
例1: 假设在对象关系型数据库中,有一对象实例的集合。每个对象实例具有n个属性。这些属性可以是关系型的、对象型的或其它。其中,记录的关键码定为属性i。并且,属性i的数据类型为POINT类型,其值如图6.7中所示(在此只列出属性i的数值)。
通过GBT索引后,我们可得到一个如图所示的3阶的GBT树
动态类型管理机制 (关系名,列数目,首列在关系属性目录表中的位置,规则链指针,终结标识,关系实例指针) 系统目录表由以下9张表组成,用其来记录整个系统所具有的关系、数据类型、函数、索引、类等等信息 (1)关系表形式: (关系名,列数目,首列在关系属性目录表中的位置,规则链指针,终结标识,关系实例指针) 其中:规则链中保存了一个关系所具有的规则在规则目录表中的位置;而终结标志则与表的继承有关。 (2)关系属性表形式: (属性名,数据类型) 其中:属性名部分用来保存属性的名字,而数据类型则用来标识一个属性的数据类型。
(3)数据类型表形式: (类型名,类型定义指针) (4)函数表形式: (函数名,参数个数,返回值类型,函数代码位置指针) (5)比较操作函数表形式: (操作符名,操作函数标识,函数代码位置指针)
(6)索引表形式: (索引方法名,索引函数标识,索引函数代码位置指针, 参数个数,比较操作符名) (7)类表形式: (类定义标志,类名,类标识号,指向类定义的指针) (8)动态数据类型索引表形式: (类型定义标志,类型名,类型标志号,指向类型定义的指针) (9)规则表形式: (主动关系名,主动列链表头指针,触发事件, 触发时刻,被动关系名,被动列链表头指针,被动事件)
当定义新的关系 新的类、 新的数据类型、 新的函数 新的操作符时, 将对系统目录表进行相应的注册或调整。
我们利用ORDDL定义了一个关系表。这个关系表有三个属性,如: create table person( name char(30), 实例: 我们利用ORDDL定义了一个关系表。这个关系表有三个属性,如: create table person( name char(30), location point, picture image ); create index on person using b_tree(location,westness); 我们不妨将location和picture分别看作是类point和image的两个对象。同时,假定在location属性上建立B树索引。其比较操作符使用用户定义的westness操作,即将这些点在向西方向上排序。
当创建这个关系时,系统在关系目录表中注册该新建关系的名,列数目等信息。并在关系属性目录表中注册该关系所具有的三个属性name,location, picture等信息。
如果这个表中有某个属性的数据类型是数据类型表中尚未出现的类型,并且也不是类目录表和动态数据类型表中的项时,系统自动产生一个出错信息,让用户提供新数据类型的定义与解释。同时,相应的在数据类型目录表中自动添加一些以前未注册过的新类型名及处理函数代码指针等信息。
当用户自定义数据类型时,在数据类型目录表中增加相应的记录。同样,对用户自定义的函数,在函数目录表中增加相应的记录。这些系统目录表是元数据,它们包含着数据库中数据的信息,对用户自定义类型和自定义函数,ORDBMS在内存中设置了存放函数信息的缓冲区。使得下一次遇到同一函数时,不必付出额外代价。
用户使用ORSQL语言对数据库进行查询, 使用如下查询程序: select name from person where contained(location, circle(‘0,0’,1)) and beard(picture) = ‘gray’;
当ORSQL语法分析器在翻译这个查询命令遇到from person时
分析器可以依据这些信息处理大部分查询语句。然而,如果查询中使用了函数,就需在函数目录表中查找。如果翻译where子句时,就需要查找contained, circle, beard函数的执行代码。并检查其参数个数、参数类型是否相配等等。同样,翻译中遇到比较操作函数,将查找比较操作函数目录表。遇到对象的信息,将查找类目录表等等。