继承
PostgreSQL实现了表的继承。主要是用于减少一些依赖关系的父子表之间的查询等问题。以下是基本的测试过程:
xxxx[xxxx@postgres]> create table city (name text, population float, altitude int);
CREATE TABLE
xxxx[xxxx@postgres]> \d city;
Table "public.city"
Column | Type | Modifiers
------------+------------------+-----------
name | text |
population | double precision |
altitude | integer |
xxxx[xxxx@postgres]>
xxxx[xxxx@postgres]>
xxxx[xxxx@postgres]> create table capitals(state char(2)) INHERITS(city);
CREATE TABLE
xxxx[xxxx@postgres]> \d capitals;
Table "public.capitals"
Column | Type | Modifiers
------------+------------------+-----------
name | text |
population | double precision |
altitude | integer |
state | character(2) |
Inherits: city
从上述的显示可知,在capital表中实际上包含了city的字段,其中capitals中只是添加了一个字段,但在表的描述中却直接继承了父类的成员。因此子表是比父表属性更多的表。
//插入数据到city表中
xxxx[xxxx@postgres]> insert into city(name, population, altitude) values ('zhangjiajie', 1.2, 1000), ('suzhou', 45, 20);
INSERT 0 2
//插入数据到capitals表中
xxxx[xxxx@postgres]> insert into capitals(name, population, altitude, state) values ('changsha', 102, 800, 'HN'), ('nanjing', 950, 30, 'JS');
INSERT 0 2
//查询city表, 其中数据包含了子表中的数据
xxxx[xxxx@postgres]> select * from city;
name | population | altitude
-------------+------------+----------
suzhou | 45 | 20
zhangjiajie | 1.2 | 1000
changsha | 102 | 800
nanjing | 950 | 30
(4 rows)
//查询子表,只包含子表中的数据
xxxx[xxxx@postgres]> select * from capitals;
name | population | altitude | state
----------+------------+----------+-------
changsha | 102 | 800 | HN
nanjing | 950 | 30 | JS
(2 rows)
//ONLY字段,只从父表中查询数据, 只包含了父表中的数据,并不包含子表中的数据。
xxxx[xxxx@postgres]> select * from only city;
name | population | altitude
-------------+------------+----------
suzhou | 45 | 20
zhangjiajie | 1.2 | 1000
(2 rows)
//更新父表中的数据属性
xxxx[xxxx@postgres]> update city SET population = 3 where name = 'zhangjiajie';
UPDATE 1
//通过父表更新子表中的数据成员
xxxx[xxxx@postgres]> update city SET population = 450 where name = 'changsha';
UPDATE 1
xxxx[xxxx@postgres]> select * from only city;
name | population | altitude
-------------+------------+----------
suzhou | 45 | 20
zhangjiajie | 3 | 1000
(2 rows)
xxxx[xxxx@postgres]> select * from city;
name | population | altitude
-------------+------------+----------
suzhou | 45 | 20
zhangjiajie | 3 | 1000
nanjing | 950 | 30
changsha | 450 | 800
(4 rows)
//删除父表中的数据
xxxx[xxxx@postgres]> delete from city where name = 'suzhou';
DELETE 1
//通过父表删除子表中的数据
xxxx[xxxx@postgres]> delete from city where name = 'nanjing';
DELETE 1
xxxx[xxxx@postgres]> select * from city;
name | population | altitude
-------------+------------+----------
zhangjiajie | 3 | 1000
changsha | 450 | 800
(2 rows)
在 PostgreSQL 里, 一个表可以从零个或多个其它表中继承属性,而且一个查询既可以引用一个表中的所有行, 也可以引用一个表的所有行加上所有其后代表的行。如需要只查询、更新、删除父表中的数据,可以采用ONLY关键字,该关键字保证删除操作只在父表中进行,而不会子表中进行。
根据之前的描述可知,对于表中的对象都存在一些系统属性,即所谓的表的系统列,其中包含了对象标识符(oid)、所属的表对象标识符(tableoid),因此在存在继承关系的一系列表中,可以通过查询tableoid标识该对象所归属的表。
xxxx[xxxx@postgres]> select c.tableoid, c.name, c.population, c.altitude from city c where altitude < 2000;
tableoid | name | population | altitude
----------+-------------+------------+----------
16397 | zhangjiajie | 3 | 1000
16403 | changsha | 450 | 800
从上面两个不同的tableoid即可知道当前的数据来自多个不同的表。
一个表可以从多个父表继承,这种情况下它拥有父表们的字段的总和。这种情况将出现如果多个表中存在相同的字段,或者同时出现在父表和子表的定义中,这些字段将被融合,即新子表中将只有一个这样的字段,但是想要融合,字段必须是相同的数据类型,负责会抛出错误。所有父表的检查约束都会自动被所有子表继承。 不过其它类型的约束没有被继承。
继承定义了之后,没有办法从一个子表上删除一个继承关系, 除非是删除整个表。如果子表存在,则不能删除父表。 如果你想删除一个表和其所有后代,一个简单的方法是用 CASCADE 选项删除全部表。
xxxx[xxxx@postgres]> drop table city; //不能直接删除父表
ERROR: cannot drop table city because other objects depend on it
DETAIL: table capitals depends on table city
table subcity depends on table capitals
HINT: Use DROP ... CASCADE to drop the dependent objects too.
xxxx[xxxx@postgres]> drop table city CASCADE; //递归的形式删除父表、子表
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table capitals
drop cascades to table subcity
DROP TABLE
注意: 权限并不是自动继承的,企图访问一个父表的用户必须要么对子表有相同的权限, 要么必须使用 "ONLY" 表示法。或者在现有的系统里创建一个新的继承关系。继承特性的一个严重的局限性是索引(包括唯一约束)和外键约束只施用于单个表, 而不包括它们的继承的子表。
分区
PostgreSQL 支持基本的表分区功能,分区的意思是把逻辑上的一个大表分割成物理上的几块儿,具有如下的好处:
>> 某些类型的查询性能提升,减少了所有的数据集合。
>> 更新的性能可以提升,表每块的索引要比整个数据集的索引小,索引如果不存放在内存中,索引的读写操作也会产生大量的磁盘访问。
>> 批量删除只需要删除某个分区,减少操作数据的集合空间。
>> 少用的数据可以存放在更慢的介质中。
分区通常只有在大数据量的情况下才有价值。通常如果表的大小超过了数据库服务器的物理内存大小,通常就可以考虑分区。PostgreSQL支持通过表继承进行分区,每个分区必须作为单独一个父类的子表创建,而父表通常是空的,存在只是为了代表整个数据集。这种实现主要依据了在PostgreSQL中的SELECT,UPDATE,DELETE操作都可以通过父类直接操作,通常分区主要进行上述三个操作,分区子类的操作也可以直接通过父类操作。
前端和后端概念
PostgreSQL采用基于消息的协议用于前后端通信(客户端和服务器)。该协议是在TCP/IP和Unix domain-socket之上的。端口5432已经在IANA(互联网地址编码分配机构)注册,通常作为服务器TCP的端口。但不限于该端口。 为了有效的服务多客户,服务器为每个客户端启动了新的后端程序,目前的实现中,当新的连接检测到以后会立即创建一个新的子进程。通常后端和服务器可交换,就像前端和客户端可交换。因此后端实际上是指该创建出来的子进程。在客户端退出之后,后端也会退出。
对象标识符(OID)
PostgreSQL 在内部使用对象标识符(OID)作为各种系统表的主键。 同时,系统不会给用户创建的表增加一个 OID 系统字段(除非在建表时声明了 WITH OIDS 或者是配置参数 default_with_oids 设置成了真)。 类型 oid 代表一个对象标识符。目前 oid 类型是用一个无符号的四字节整数实现的。 因此,它是不够用于提供大数据库范围内的唯一性保证的, 甚至在单个的大表中也不行。因此,我们不鼓励在用户创建的表中使用 OID 字段做主键。OID 最好只是用于引用系统表。