1.Tablespace
表空间像是文件系统上的一个虚拟目录,允许DBA在文件系统上指定不同数据库对象的文件位置,表空间创建后,就可以在创建数据库对象时引用。
使用表空间有如下两个好处,首先,如果初始化时指定的数据目录所在的磁盘分区或卷被用光,需要扩充空间,就可以指定新的表空间来存放数据;其次,可以根据数据对象对磁盘IO的要求不同来指定不同表空间,如对应归档数据,存放在读写慢的磁盘,对应频繁访问的核心数据,存放在高性能磁盘。
2.表空间测试
#创建目录
[root@node1 bin]# mkdir /pg_tbs
[root@node1 bin]# chown pg14:pg14 /pg_tbs/
#创建表空间
postgres=# create tablespace tbs_test location '/pg_tbs';
CREATE TABLESPACE
#创建后后再指定的目录下生成一个带有版本号的目录
[pg14@node1 pg_tbs]$ ll
total 0
drwx------ 2 pg14 pg14 6 Aug 19 07:54 PG_14_202107181
#数据库内查看表空间
postgres=# \db
List of tablespaces
Name | Owner | Location
------------+----------+----------
pg_default | postgres |
pg_global | postgres |
tbs_test | postgres | /pg_tbs
#在表空间上创建一个数据库
postgres=# create user lys superuser password 'lys';
CREATE ROLE
postgres=# create database test with owner=lys tablespace tbs_test;
CREATE DATABASE
[pg14@node1 pg_tbs]$ cd /pg_tbs/PG_14_202107181/
[pg14@node1 PG_14_202107181]$ ll
total 12
drwx------ 2 pg14 pg14 8192 Aug 19 08:00 16387
16387 即为数据库test的oid
postgres=# select oid,datname from pg_database where datname='test';
oid | datname
-------+---------
16387 | test
#在test数据库下创建一个表t1
postgres=# \c test lys
You are now connected to database "test" as user "lys".
test=# create table t1 (id int,name varchar(10));
CREATE TABLE
[pg14@node1 16387]$ pwd
/pg_tbs/PG_14_202107181/16387
[pg14@node1 16387]$ ll 16388*
-rw------- 1 pg14 pg14 0 Aug 19 08:03 16388
未插入数据前,数据文件大小为0
#向表内插入2条数据
test=# insert into t1 values(1,'aaa');
INSERT 0 1
test=# insert into t1 values(2,'bbb');
INSERT 0 1
[pg14@node1 16387]$ ll 16388*
-rw------- 1 pg14 pg14 8192 Aug 19 08:12 16388
当一个表空间被创建时,会在$PGDATA/pg_tblspc目录下创建一个名为表空间oid的符号链接,执行该表空间的目录位置
[root@node1 pgdata02]# cd pg_tblspc/
[root@node1 pg_tblspc]# ls
16385
[root@node1 pg_tblspc]# ll
total 0
lrwxrwxrwx 1 pg14 pg14 7 Aug 19 07:54 16385 -> /pg_tbs
在PostgreSQL中可以使用pg_relation_filepath函数查看对象文件所在位置
test=# select pg_relation_filepath('t1');
pg_relation_filepath
---------------------------------------------
pg_tblspc/16385/PG_14_202107181/16387/16388
如果我们在tbs_test下创建另一个新表,但新表所属的数据库创建在默认表空间pg_default,那么pg会首先在表空间目录下创建名称与所属数据相同oid的子目录,然后将新表文件放在刚创建的目录下
test=# \c postgres postgres
You are now connected to database "postgres" as user "postgres".
postgres=# create table t2(id int,name varchar(10)) tablespace tbs_test;
CREATE TABLE
postgres=# select pg_relation_filepath('t2');
pg_relation_filepath
---------------------------------------------
pg_tblspc/16385/PG_14_202107181/13892/16391
(1 row)
#13892为postgres数据库的oid,16391为t2表oid
postgres=# select oid,datname from pg_database where datname='postgres';
oid | datname
-------+----------
13892 | postgres
[pg14@node1 16387]$ cd /pgdata02/pg_tblspc/16385/PG_14_202107181/13892/
[pg14@node1 13892]$ ll
total 0
-rw------- 1 pg14 pg14 0 Aug 19 08:47 16391
3.文件和分支
在PostgreSQL中,一个表一般由一个或多个数据文件组成,这些数据文件又由后缀被划分为多个分支(fork)。如空闲空间位图,后缀为_fsm;可视位图,后缀为 _vm;
还有一个不常用的分支为init分支,后缀为_init,对于在建表时指定unlogged参数的表和对应的索引,这些表的所以操作都不会写入wal日志,这样存储可以提高效率,但是在发生故障时,您将无法恢复一致的数据。因此,Postgre在恢复过程中删除所有这些对象的分支,并用初始化分支覆盖主分支,从而创建一个虚拟文件。
最开始时,一个表创建时,只会有一个名为oid的主分支,随着表数据越来越多,当主分支超过1G时(编译时由–with-segsize 指定),主分支会另创建一个文件,名为oid.1,此文件再超过1G时,创建oid.2。随着表数据增多,也会创建_fsm和vm分支,增长规则也会跟主分支一样。
#创建测试表
create table if not exists t_test(
id serial ,
username varchar(255),
password varchar(255),
create_time date,
dr char(1)
);
#插入数据100万数据
insert into t_test select generate_series(1,100*10000),'username'||round(random()*1000000),'password'||round(random()*1000000),now(),0;
test=# select pg_relation_filepath('t_test');
pg_relation_filepath
---------------------------------------------
pg_tblspc/16385/PG_14_202107181/16387/16404
#查看分支
[pg14@node1 pgdata02]$ ll pg_tblspc/16385/PG_14_202107181/16387/16404*
-rw------- 1 pg14 pg14 76423168 Aug 19 09:48 pg_tblspc/16385/PG_14_202107181/16387/16404
-rw------- 1 pg14 pg14 40960 Aug 19 09:48 pg_tblspc/16385/PG_14_202107181/16387/16404_fsm
多了空闲位图分支
#修改一条数据
test=# update t_test set dr='1' where id=round(random()*1000000);
UPDATE 1
[pg14@node1 pgdata02]$ ll pg_tblspc/16385/PG_14_202107181/16387/16404*
-rw------- 1 pg14 pg14 76423168 Aug 19 09:51 pg_tblspc/16385/PG_14_202107181/16387/16404
-rw------- 1 pg14 pg14 40960 Aug 19 09:48 pg_tblspc/16385/PG_14_202107181/16387/16404_fsm
-rw------- 1 pg14 pg14 8192 Aug 19 09:49 pg_tblspc/16385/PG_14_202107181/16387/16404_vm
多了可见位图分区
#创建unlogged表
test=# create unlogged table t_unlog(id int,name varchar(10));
CREATE TABLE
test=# insert into t_unlog values(1,'aaa');
INSERT 0 1
test=# select pg_relation_filepath('t_unlog');
pg_relation_filepath
---------------------------------------------
pg_tblspc/16385/PG_14_202107181/16387/16410
#查看分支
[pg14@node1 pgdata02]$ ll pg_tblspc/16385/PG_14_202107181/16387/16410*
-rw------- 1 pg14 pg14 8192 Aug 19 09:55 pg_tblspc/16385/PG_14_202107181/16387/16410
-rw------- 1 pg14 pg14 0 Aug 19 09:54 pg_tblspc/16385/PG_14_202107181/16387/16410_init