用户表空间也是数据库创建时自动创建的,表空间名称为USERSPACE1,数据库中的用户表默认存放于这个表空间中,用户表空间是可选的,一个数据库可以有多个用户表空间。必须至少有一个用户表空间(没有用户表空间的话数据库无法存放用户数据)。用户表空间也可以是SMS表空间或DMS表空间,通常使用DMS表空间。
临时表空间(TEMPSPACE)
临时表空间也是数据库创建时自动创建的,数据库管理器使用临时表空间在执行SQL操作时存储临时数据,例如排序,表重组,索引创建以及表链接等操作所产生的中间表都由临时表空间存储,数据库必须至少有一个临时表空间,也可以有多个。创建数据库时默认创建的临时表空间名称为TEMPSPACE1,且为SMS表空间。但是这个表空间的名称可以是任意的,当另外的临时表空间被创建后,该默认临时表空间也可以被删除。(但必须保证数据库有一个临时表空间)。临时表空间也可以是DMS表空间。另外,DB2支持系统临时表空间和用户临时表空间两种类型,系统临时表空间必须存在,用户临时表空间可以有0个或多个,用来声明临时表。
除了根据管理和用途划分表空间类型,还可以根据容量将表空间划分为常规表空间和大型表空间。但是这里的常规表空间和大型表空间都是针对DMS表空间而言,SMS表空间大小上限还不及常规表空间。
行指针
首先考虑一个问题:逻辑上,数据以数据行(元组)的形式保存在数据库的表中,但物理上,根据数据库磁盘存储的知识(数据库深入学习笔记----磁盘存储内部结构),数据肯定是存储在数据文件上的,确切的说是存储在数据块(页)上。那么,数据库是如何根据表中的行寻址到物理磁盘上数据页中的数据呢?
Oracle和DB2的解决方案是使用一种新的数据结构:行指针(或行指示器),Oracle数据库中称为ROWID,DB2中称为RID。在实际的数据库表中,每张表都会附加一个特定的隐藏列,即行指针列,也就是说,每一行数据都有一个行指针属性,它指向该行数据在物理磁盘中的具体位置。实际上不管是Oracle还是DB2,行指针都是可以参与SQL查询的(毕竟是有效的行属性。Oracle中的ROWID可以直接当作属性进行查询,DB2中则需要使用rid函数查询RID)如下图是DB2数据库的RID格式:
常规表空间
在DB2 V9之前,RID具有4个字节(32位)长度,其中3个字节用于数据页寻址,最后1个字节用于数据页内槽号寻址(《数据库深入学习笔记----磁盘存储内部结构》介绍过,每一行数据都是一条记录,存储在数据页的数据存储空间里,每一条记录都对应槽目录中的一个槽号)。
由RID的结构我们就可以计算出数据页能够容纳的记录数(行数)和表空间的容量了:
因为一个RID只有1个字节(8位)槽号,所以,一个数据页存储的记录数的最大值为255条(2的8次方-1,为什么要减1?这是因为磁盘存储那篇文章已经讲过,有的数据页是会有一个可用空间控制记录(FSCR)的,所以需要预留)。(说明:8位能寻址的范围就是0-255,槽号编号就只能是0-255,如果记录再多,就无法被槽目录编号了,无法被寻址,数据存了也是白存。)
同理,可以根据3个字节的页号,得出一个表空间最多能容纳16777216(16M,2的24次)个数据页。那么,如果是一个数据页4KB的话,表空间大小就是16M*4KB=64GB了。如果一个数据页32KB的话,就是16M*32KB=512GB。(DB2表空间支持的页面大小有4KB,8KB,16KB和32KB四种,一个表空间只能使用一种大小的数据页)
可以想象,如果数据库表中的行长度(一行所占用的存储空间)太小,由于一个数据页理论上最多只能存储255行(实际上,每一页允许存储的记录数通常少于255条),那必然造成数据页空间的浪费,比如4KB页,长度为12B的行存满页面也只占用12B*255=3060B的空间,剩下的1036KB多的空间只能浪费。下表显示了页面空间被浪费前的最小行长度:
一旦表空间中满足了最大页限制,有以下三种方案可供选择:
1.在视图中把这些表连接起来(多个表空间中的表在视图中合在一起);
2.使用DB2的数据库分区功能(DPF,Database Partitioning Feature),横跨多个分区将数据进行组合;
3.使用范围分区表。
无论哪种方案都需要将一些数据进行迁移并可能对应用程序进行修改,这无疑是很繁琐的。
大型表空间