红书推荐系列(四):The Design of Postgres
前
INGRES于1975-1977年在加州大学开发,后来又做了分布式、抽象数据等一系列的扩展,但人们很快发现在INGRES现有的架构上很难添加一些新的功能,所以开发团队重新开发了Postgres,Postgre后来又被PostgreSQL取代。
Postgres最大的贡献是abstract data type (ADT) system,在主流的数据库中添加用户定义类型和函数用的都是Postgres的模型。
设计目标
Postgres设计时,关系型数据模型已经被证明非常适合商务数据处理,但是这种模型不适合市场上的许多软件(比如CAD中需要存储的图形和图形数据)。
Postgres的第一个设计目标就是支持复杂对象。虽然复杂对象可以通过关系表模拟出来,但是这样性能往往是不可接受的。比如在传统的数据库中,创建物体有以下语句:
POLYGON(id, other fields)
CIRCLE(id, other fields)
LINE(id, other fields)
要显示一个物体,还需要颜色、位置、缩放等信息。我们可以把它们存入一个表中:
DISPLAY(color, position, scaling, object-type, object-id)
object-type指定对象在哪个表中(POLYGON、CIRCLE、LINE),object-id指定对象的标识符。那么我们每次取数据的时候都会遍历所有的表:
foreach OBJ in {POLYGON, CIRCLE, LINE} do range of O is OBJ range of D is DISPLAY retrieve (D.all, O.all) where D.object-id = O.id and D.object-type = OBJ
显然,无论DBMS有多快,都不能实时的找到需要的所有结果,因为这样的查询可以任意多。
第二个设计目标是扩展性。传统的DBMS只提供了少量的内置数据类型和访问方法。比如查找图形类型的数据,这时传统的B+树很难满足查找需求,而比较适合的K-D-R树和R树却比较适合。这就要求数据库能够提供易用的扩展接口。
第三个目标是支持alerters、triggers和规则系统。
第四个目标是减少DBMS在crash recovery的代码量。
第五个目标是尽量使用最新技术。
最后一个目标是减少对关系模型的修改。
POSTQUEL
这一节介绍Postgres的查询语言。
数据定义
Postgres提供了一些内置类型:
- 整数
- 浮点数
- 固长字符串
- 变长任意类型数组
- POSTQUEL
- procedure
Scalar类型(1、2、3)可以通过点标记访问(EMP.name)。
变长数组(4)通过下标访问(EMP.picture[i])。
POSTQUEL包含一串数据操作命令,同样也是通过点标记访问。但是如果POSTQUEL中包含取数据命令,那么可以在命令后面继续加点标记(EMP.hobbies.battingavg)。
Procedure包含用通用编程语言编写的程序。
POSTQUEL和procedure都可以通过Execute命令来执行,比如有一个表:
EMP(name, age, salary, hobbies, dept)
那么可以通过以下命令来执行查询:
EXECUTE(EMP.hobbies) WHERE EMP.name = "Smith"
因为命令包含的取得数据的命令可能不止一条,所以取得的tuple的类型可能不同(因此编程语言接口必须要提供动态决定类型的机制)。
Complex Objects
Posgres的复杂对象可以通过POSTQUEL和procedure表示。以上面的POLYGON,CIRCLE,LINE为例,一个对象可以通过这些类型组成。首先,定义一个对象的定义为:
CREATE OBJECT(name=char[10], obj=postquel)
那么我们定义一个苹果和一个橘子对象,如下:
| Name | OBJ |
| apple |
RETRIEVE(POLYGON.all) WHERE POLYGON.id = 10 RETRIEVE(CIRCLE.all) WHERE CIRCLE.id = 40 |
| orange |
RETRIEVE(LINE.all) WHERE LINE.id = 17 RETRIEVE(POLYGON.all) WHERE POLYGON.id = 10 |
通过定义procedure还可以支持更多的对象表示方法,比如对于上面的对象我们想要将它显示出来,那么创建对象的方法如下:
CREATE OBJECT(name=char[10], obj=postquel, display=cproc)
cproc对于所有的OBJECT相同,所以不需要每个对象都存储一个,只存一个在系统表中即可。
这一部分感觉paper讲的不是很全面,有兴趣的读者可以去PostgreSQL官网文档查找更详细的资料。
Time Varying Data
POSTQUEL允许用户保存查询历史数据和版本。历史数据可以通过指定时间来访问,比如:
RETRIEVE(E.all) FROM E IN EMP["7 January 2020"]
命令取出了2020年1月7日的所有数据。
迭代查询、触发器、提醒、规则
这里部分和PostgreSQL或者现代的其它DBMS在语法差别有点大,这里就略过了。
SYSTEM ARCHITECTURE
不得不说,读这篇paper真的恼人,就像老太太的袜子一样,又长又臭。
Process Structure
Postgre采用多进程模式查询数据,其好处可以看红书推荐系列(二)。
Query Processing
Postgres的query optimizer比较传统,但做了三点扩展。第一,optimizer必须能利用用户定义的访问方法。第二,要一个有效通用的方法来支持POSTQUEL和procedure。第三,需要一个高效的方法来支持trigger和rules。
Support for New Types
支持访问方法的基本思想是实现一些特定的运算符,比如在B-树中,需要的运算符为{<, =, >, >=, <=}。这些运算符符合一些基本定律,包括传递性。
Support for Procedural Data
优化查询性能的方法是预计算和缓存结果。其中预计算的分为两步:
- 编译POSTQUEL命令的访问方案。
- 执行访问方案。
总结
Postgres的SQL语法一言难尽,虽然已经到了80年代,但SQL语法设计仍然体现出一些糟糕的地方。总之,这篇paper最值得看的地方就是抽象数据是怎么样用关系型数据有效表示的,其它的部分就可有可无了。

浙公网安备 33010602011771号