PG 管理表空間

創建數據庫或者數據表(包括索引)的時候,可以爲其指定一個表空間(tablespace)。表空間決定了這些對象在文件系統中的存儲路徑。現在我們來學習一些關於表空間的知識。

基本概念

在 PostgreSQL 中,表空間(tablespace)表示數據文件的存放目錄,這些數據文件代表了數據庫的對象,例如表或索引。當我們訪問表時,系統通過它所在的表空間定位到對應數據文件所在的位置。
PostgreSQL tablespace

PostgreSQL 中的表空間與其他數據庫系統不太一樣,它更偏向於一個物理上的概念。

表空間的引入爲 PostgreSQL 的管理帶來了以下好處:

  • 如果數據庫集羣所在的初始磁盤分區或磁盤卷的空間不足,又無法進行擴展,可以在其他分區上創建一個新的表空間以供使用。
  • 管理員可以根據數據庫對象的使用統計優化系統的性能。例如,可以將訪問頻繁的索引存放到一個非常快速且可靠的磁盤上,比如昂貴的固態硬盤。與此同時,將很少使用或者對性能要求不高的歸檔數據表存儲到廉價的低速磁盤上。

PostgreSQL 在集羣初始化時將所有的數據文件和配置文件存儲到它的數據目錄中,通常是環境變量 PGDATA 的值。默認創建了兩個表空間:

  • pg_default, template1 和 template0 默認的表空間,也是創建其他數據庫時的默認表空間;對應的目錄爲 PGDATA/base。
  • pg_global,用於存儲一些集羣級別的共享系統表(system catalogs),例如 pg_database、pg_control;對應的目錄爲 PGDATA/global。

初始安裝後,使用 psql 查詢默認創建的表空間:

postgres=# \db
              List of tablespaces
    Name    |  Owner   |        Location        
------------+----------+------------------------
 pg_default | postgres | 
 pg_global  | postgres | 
(2 rows)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

同時也可以通過操作系統命令查看相應的目錄:

-bash-4.2$ ls -l /var/lib/pgsql/11/data/
total 60
drwx------. 8 postgres postgres    80 Jan  8 05:53 base
-rw-------. 1 postgres postgres    30 Jan 13 00:00 current_logfiles
drwx------. 2 postgres postgres  4096 Jan 12 16:28 global
drwx------. 2 postgres postgres   188 Jan 10 00:00 log
drwx------. 2 postgres postgres     6 Jan  4 16:56 pg_commit_ts
drwx------. 2 postgres postgres     6 Jan  4 16:56 pg_dynshmem
-rw-------. 1 postgres postgres  4305 Jan  4 17:58 pg_hba.conf
-rw-------. 1 postgres postgres  1636 Jan  4 16:56 pg_ident.conf
drwx------. 4 postgres postgres    68 Jan 13 13:55 pg_logical
drwx------. 4 postgres postgres    36 Jan  4 16:56 pg_multixact
drwx------. 2 postgres postgres    18 Jan  4 17:58 pg_notify
drwx------. 2 postgres postgres     6 Jan  4 16:56 pg_replslot
drwx------. 2 postgres postgres     6 Jan  4 16:56 pg_serial
drwx------. 2 postgres postgres     6 Jan  4 16:56 pg_snapshots
drwx------. 2 postgres postgres     6 Jan  4 17:58 pg_stat
drwx------. 2 postgres postgres   105 Jan 13 16:57 pg_stat_tmp
drwx------. 2 postgres postgres    18 Jan  4 16:56 pg_subtrans
drwx------. 2 postgres postgres    19 Jan 12 15:42 pg_tblspc
drwx------. 2 postgres postgres     6 Jan  4 16:56 pg_twophase
-rw-------. 1 postgres postgres     3 Jan  4 16:56 PG_VERSION
drwx------. 3 postgres postgres    60 Jan  4 16:56 pg_wal
drwx------. 2 postgres postgres    18 Jan  4 16:56 pg_xact
-rw-------. 1 postgres postgres    88 Jan  4 16:56 postgresql.auto.conf
-rw-------. 1 postgres postgres 23800 Jan  4 17:50 postgresql.conf
-rw-------. 1 postgres postgres    58 Jan  4 17:58 postmaster.opts
-rw-------. 1 postgres postgres   109 Jan  4 17:58 postmaster.pid
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

其中的 base 和 global 目錄分別對應表空間 pg_default 和 pg_global。關於這些文件和目錄的具體介紹,可以參考官方文檔

創建表空間

創建新的表空間使用CREATE TABLESPACE語句:

CREATE TABLESPACE tablespace_name
OWNER user_name
LOCATION 'directory';
  • 1
  • 2
  • 3

表空間的名稱不能以 ‘pg_’ 開頭,它們是系統表空間的保留名稱;LOCATION 參數必須指定絕對路徑名,指定的目錄必須是一個已經存在的空目錄,PostgreSQL 操作系統用戶(postgres)必須是該目錄的擁有者,以便能夠進行文件的讀寫。

接下來,我們使用目錄 /var/lib/pgsql/ 創建一個新的表空間 app_tbs。先創建所需的目錄:

[root@centos7 ~]# su - postgres
Last login: Wed Jan  9 09:29:19 EST 2019 on pts/0
-bash-4.2$ mkdir /var/lib/pgsql/app_tbs
-bash-4.2$ ll
total 0
drwx------. 4 postgres postgres 51 Jan  4 16:56 11
drwxr-xr-x. 2 postgres postgres  6 Jan 12 15:39 app_tbs
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

注意目錄的所有者和權限。然後使用具有 CREATEDB 權限的用戶創建表空間,此處我們使用 postgres 執行以下操作:

postgres=# CREATE TABLESPACE app_tbs LOCATION '/var/lib/pgsql/app_tbs';
CREATE TABLESPACE
postgres=# \db
              List of tablespaces
    Name    |  Owner   |        Location        
------------+----------+------------------------
 app_tbs    | postgres | /var/lib/pgsql/app_tbs
 pg_default | postgres | 
 pg_global  | postgres | 
(3 rows)

postgres=# select oid,* from pg_tablespace;
oid | spcname | spcowner | spcacl | spcoptions
-------±-----------±---------±-------±-----------
1663 | pg_default | 10 | |
1664 | pg_global | 10 | |
16470 | app_tbs | 10 | |
(3 rows)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

我們查看一下操作系統中的變化:

-bash-4.2$ ls -l /var/lib/pgsql/app_tbs/
total 0
drwx------. 2 postgres postgres 6 Jan 12 15:42 PG_11_201809051
  • 1
  • 2
  • 3

在表空間對應的目錄中,創建一個特定版本的子目錄(PG_‘Major version’_‘Catalogue version number’)。

與此同時,在數據目錄下的 pg_tblspc 子目錄中,創建了一個指向表空間目錄的符號鏈接,名稱爲表空間的 OID(16470):

-bash-4.2$ ls -l /var/lib/pgsql/11/data/pg_tblspc/
total 0
lrwxrwxrwx. 1 postgres postgres 22 Jan 12 15:42 16470 -> /var/lib/pgsql/app_tbs
  • 1
  • 2
  • 3

默認情況下,執行CREATE TABLESPACE語句的用戶爲該表空間的擁有者,也可以使用OWNER選項指定擁有者。

對於普通用戶,需要授予表空間上的對象創建權限才能使用該表空間。我們爲用戶 tony 授予表空間 app_tbs 上的使用權限:

postgres=# GRANT CREATE ON TABLESPACE app_tbs TO tony;
GRANT
postgres=# \db+
                                          List of tablespaces
    Name    |  Owner   |        Location        |  Access privileges  | Options |  Size   | Description 
------------+----------+------------------------+---------------------+---------+---------+-------------
 app_tbs    | postgres | /var/lib/pgsql/app_tbs | postgres=C/postgres+|         | 0 bytes | 
            |          |                        | tony=C/postgres     |         |         | 
 pg_default | postgres |                        |                     |         | 46 MB   | 
 pg_global  | postgres |                        |                     |         | 574 kB  | 
(3 rows)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

使用 tony 用戶連接到數據庫 testdb,然後在表空間 app_tbs 中創建一個新的數據表 t:

testdb=> CREATE TABLE t(id int) tablespace app_tbs;
CREATE TABLE

testdb=> SELECT * FROM pg_tables WHERE tablename=‘t’;
schemaname | tablename | tableowner | tablespace | hasindexes | hasrules | hastriggers | rowsecurity
------------±----------±-----------±-----------±-----------±---------±------------±------------
public | t | tony | app_tbs | f | f | f | f
(1 row)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

PostgreSQL 支持在CREATE DATABASECREATE TABLECREATE INDEX以及ADD CONSTRAINT語句中指定 tablespace_name 選項,覆蓋默認的表空間(pg_default)。也可以使用相應的ALTER ...語句將對象從一個表空間移到另一個表空間。

如果不想每次創建對象時手動指定表空間,可以使用配置參數 default_tablespace:

testdb=> SET default_tablespace = app_tbs;
SET
testdb=> CREATE TABLE t1(id int);
CREATE TABLE
testdb=> SELECT * FROM pg_tables WHERE tablename='t1';
 schemaname | tablename | tableowner | tablespace | hasindexes | hasrules | hastriggers | rowsecurity 
------------+-----------+------------+------------+------------+----------+-------------+-------------
 public     | t1        | tony       | app_tbs    | f          | f        | f           | f
(1 row)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

對於臨時表和索引,使用配置參數 temp_tablespaces 進行控制,參考官方文檔

修改表空間

如果需要修改表空間的定義,可以使用 ALTER TABLESPACE 語句:

ALTER TABLESPACE name RENAME TO new_name;

ALTER TABLESPACE name OWNER TO { new_owner | CURRENT_USER | SESSION_USER };

ALTER TABLESPACE name SET ( tablespace_option = value [, ... ] );
ALTER TABLESPACE name RESET ( tablespace_option [, ... ] );

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

第一個語句用於表空間的重命名;第二個語句用於修改表空間的擁有者;最後兩個語句用於設置表空間的參數。

我們將表空間 app_tbs 重命名爲 tony_tbs:

postgres=# \db
              List of tablespaces
    Name    |  Owner   |        Location        
------------+----------+------------------------
 app_tbs    | postgres | /var/lib/pgsql/app_tbs
 pg_default | postgres | 
 pg_global  | postgres | 
(3 rows)

postgres=# ALTER TABLESPACE app_tbs RENAME TO tony_tbs;
ALTER TABLESPACE
postgres=# \db
List of tablespaces
Name | Owner | Location
------------±---------±-----------------------
pg_default | postgres |
pg_global | postgres |
tony_tbs | postgres | /var/lib/pgsql/app_tbs
(3 rows)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

只有表空間的擁有者或超級用戶才能修改表空間的定義。

接下來將表空間 tony_tbs 的擁有者修改爲 tony:

postgres=# ALTER TABLESPACE tony_tbs OWNER TO tony;
ALTER TABLESPACE
postgres=# \db
              List of tablespaces
    Name    |  Owner   |        Location        
------------+----------+------------------------
 pg_default | postgres | 
 pg_global  | postgres | 
 tony_tbs   | tony     | /var/lib/pgsql/app_tbs
(3 rows)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

PostgreSQL 支持設置的表空間參數包括 seq_page_costrandom_page_cost 以及 effective_io_concurrency。它們用於查詢計劃器選擇執行計劃時的代價評估。

目前,PostgreSQL 還不支持使用語句修改表空間的存儲路徑。但是,可以通過手動的方式移動表空間的位置:

  1. 停止 PostgreSQL 服務器進程;
  2. 移動文件系統中的數據文件位置;
  3. 修改 PGDATA/pg_tblspc 目錄中的符號鏈接文件(需要提前獲取文件名),指向新的目錄;
  4. 啓動 PostgreSQL 服務器進程。

首先,停止 PostgreSQL 服務器進程:

-bash-4.2$ whoami
postgres
-bash-4.2$ /usr/pgsql-11/bin/pg_ctl stop
waiting for server to shut down.... done
server stopped
  • 1
  • 2
  • 3
  • 4
  • 5

然後,將操作系統中的 /var/lib/pgsql/app_tbs/ 目錄移動到 /var/lib/pgsql/tony_tbs:

-bash-4.2$ mv /var/lib/pgsql/app_tbs/ /var/lib/pgsql/tony_tbs
  • 1

更新符號鏈接文件,執行新的目錄:

-bash-4.2$ ln -snf /var/lib/pgsql/tony_tbs /var/lib/pgsql/11/data/pg_tblspc/16470
-bash-4.2$ ls /var/lib/pgsql/11/data/pg_tblspc/16470 -l
lrwxrwxrwx. 1 postgres postgres 23 Jan 14 20:21 /var/lib/pgsql/11/data/pg_tblspc/16470 -> /var/lib/pgsql/tony_tbs
  • 1
  • 2
  • 3

最後,重新啓動 PostgreSQL 服務器進程:

-bash-4.2$ /usr/pgsql-11/bin/pg_ctl start
waiting for server to start....2019-01-14 20:23:43.628 EST [20994] LOG:  listening on IPv4 address "192.168.56.103", port 5432
2019-01-14 20:23:43.632 EST [20994] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
2019-01-14 20:23:43.639 EST [20994] LOG:  listening on Unix socket "/tmp/.s.PGSQL.5432"
2019-01-14 20:23:43.661 EST [20994] LOG:  redirecting log output to logging collector process
2019-01-14 20:23:43.661 EST [20994] HINT:  Future log output will appear in directory "log".
 done
server started
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

確認是否修改成功:

postgres=# \db
               List of tablespaces
    Name    |  Owner   |        Location         
------------+----------+-------------------------
 pg_default | postgres | 
 pg_global  | postgres | 
 tony_tbs   | tony     | /var/lib/pgsql/tony_tbs
(3 rows)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

注意,在 PostgreSQL 9.1 及更早的版本中,還需要用新的目錄更新系統表 pg_tablespace,否則,pg_dump 將繼續使用舊的表空間位置。

刪除表空間

對於不再需要的表空間,可以使用DROP TABLESPACE語句進行刪除:

DROP TABLESPACE [ IF EXISTS ] name;
  • 1

IF EXISTS可以避免刪除不存在的表空間時產生錯誤信息。

只有表空間的擁有者或超級用戶能夠刪除表空間。刪除表空間之前需要確保其中不存在任何數據庫對象,否則無法刪除。

testdb=> DROP TABLESPACE tony_tbs;
ERROR:  tablespace "tony_tbs" is not empty
  • 1
  • 2

無法刪除表空間 tony_tbs 是因爲數據庫 testdb 中存在使用該表空間創建的對象。

testdb=> SELECT ts.spcname,
testdb->        cl.relname
testdb->   FROM pg_class cl
testdb->   JOIN pg_tablespace ts ON cl.reltablespace = ts.oid
testdb->  WHERE ts.spcname = 'tony_tbs';
 spcname  | relname 
----------+---------
 tony_tbs | t
 tony_tbs | t1
(2 rows)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

可以將這些對象刪除,或者移動到其他表空間中,然後再刪除表空間:

testdb=> DROP TABLE t, t1;
DROP TABLE
testdb=> DROP TABLESPACE tony_tbs;
DROP TABLESPACE
testdb=> \db
       List of tablespaces
    Name    |  Owner   | Location 
------------+----------+----------
 pg_default | postgres | 
 pg_global  | postgres | 
(2 rows)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

其他數據庫中也可能存在依賴於被刪除表空間的對象,同樣需要先進行處理,才能刪除表空間。

刪除表空間時,同時會刪除文件系統中對應的表空間子目錄。

關於表空間,先了解這麼多。接下來我們探討一下如何防止因系統崩潰、硬件故障或者用戶錯誤可能帶來的數據丟失,也就是 PostgreSQL 數據庫的備份與恢復

人生本來短暫,你又何必匆匆!點個贊再走吧!

                                </div>
            <link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-e9f16cbbc2.css" rel="stylesheet">
                </div>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章