疑問
前幾天PG學習微信群有人在問“pg_class 儲存了物件和名稱空間,表空間的對應關係,為什麼沒有和資料庫的關係?我想查資料庫下面有多少物件,找不到資料庫和物件的關係?”
簡而言之;PostgreSQL資料庫和物件的關係;提這個問題的同學;應該是想知道
PostgreSQL例項中資料庫之間的關係,以及資料庫和物件的關係。
至於能否有這樣的SQL;容我一步一步探索
探索
1、探索PG的邏輯結構
邏輯結構圖
上圖解析:
- 第一層是例項(Instance)。
- 第二層是資料庫(Database);一個例項下有多個資料庫;每個資料庫之間是完全獨立的。
- 第三層是Schema;資料庫下面有多個Schema;其中“public” 是資料庫建立時產生的。
- 每個Schema下面可以建立表,檢視,索引,函式,序列,物化檢視,外部表等等。
由於在PostgreSQL每個資料庫是完全獨立的;這可以解釋另外一個問題(為什麼訪問同一個例項下其他資料庫為什麼要借用 dblink或者fdw介面?)。
這時可能會有學MYSQL同學會問到;(為什麼在MYSQL中可以訪問同例項下其他資料庫?)。其實MYSQL跟PostgreSQL邏輯結構不一樣;其中MYSQL例項中的資料庫相當於PostgreSQL上圖的第三層的Schema。
2、探索PG資料庫中schema
瞭解過PostgreSQL的同學都知道;我們通過系統表pg_database可以查到資料庫,通過系統表pg_class可以查到資料庫object。
postgres=# select datname, oid from pg_database where datname = 'postgres';
datname | oid
----------+-------
postgres | 13543
(1 row)
postgres=# select relname, oid from pg_class where oid = 't1' :: regclass;
relname | oid
---------+-------
t1 | 32768
(1 row)
而pg_database、pg_class存放在一個名為pg_catalog的Schema下。其中pg_catalog是系統級的schema,用於儲存系統函式和系統後設資料、而每個 database 建立好後,預設會有3個Schema。
-
一個名為pg_catalog,用於儲存Postgresql系統自帶的函式,表,系統檢視,資料型別轉換器以及資料型別定義等後設資料
-
一個名為information_schema,用於儲存所需求提供的後設資料查詢檢視,目的是以符合ANSI SQL規範,可單獨刪除
-
一個名為public,用於儲存使用者建立的資料表。不建議專案的表存放在public下,1、是資料安全;2、表存放混亂;不利於後期維護等等
檢視schema
-- 通過元命令檢視
lottu=# \dn
List of schemas
Name | Owner
--------+----------
public | postgres
-- 檢視隱藏的schema
lottu=# select table_schema
lottu-# from information_schema.tables
lottu-# group by table_schema;
table_schema
--------------------
information_schema
pg_catalog
(2 rows)
-- 系統表存放的schema是在pg_catalog下;
lottu=# \d pg_catalog.pg_class
lottu=# \d pg_catalog.pg_database
--這裡我們先丟擲一個問題;後面解析;每個資料庫的pg_class是同一個嗎?
3、探索PG資料庫中catalog
我們知道新建一個資料庫會在表空間對應的目錄下建立一個 oid(資料庫oid)的目錄;用於存放這個資料庫對應的資料庫檔案。
-- 例如資料庫lottu
lottu=# select oid, datname from pg_database where datname='lottu';
oid | datname
-------+---------
32771 | lottu
(1 row)
--對應的目錄就會有一個32771的資料夾
[postgres@node3 ~]$ ll /data/postgres/data/base/
total 32
drwx------. 2 postgres postgres 4096 Sep 16 10:54 1
drwx------. 2 postgres postgres 4096 Sep 16 10:54 13542
drwx------. 2 postgres postgres 12288 Sep 21 11:44 13543
drwx------. 2 postgres postgres 12288 Sep 21 14:33 32771
-- 在 資料庫lottu中;其中的table_catalog
lottu=# select table_catalog
lottu-# from information_schema.tables
lottu-# group by table_catalog;
table_catalog
---------------
lottu
(1 row)
-- 在資料庫 postgres中;其中table_catalog是postgres。
lottu=# \c postgres
You are now connected to database "postgres" as user "postgres".
postgres=# select table_catalog
from information_schema.tables
group by table_catalog;
table_catalog
---------------
postgres
(1 row)
通過上述實驗;我們可以瞭解到PG同例項下資料庫之間不僅物理結構完全獨立,邏輯結構也是完全獨立。這個不僅作用於使用者表,還作用於系統表。現在來解析上面丟擲的問題“每個資料庫的pg_class是同一個嗎”?
-- 在postgres資料庫中
postgres=# select table_catalog, table_schema, table_name, table_name :: regclass ::oid from information_schema.tables where table_name = 'pg_class';
table_catalog | table_schema | table_name | table_name
---------------+--------------+------------+------------
postgres | pg_catalog | pg_class | 1259
(1 row)
--在 lottu 資料庫中
lottu=# select table_catalog, table_schema, table_name, table_name :: regclass ::oid from information_schema.tables where table_name = 'pg_class';
table_catalog | table_schema | table_name | table_name
---------------+--------------+------------+------------
lottu | pg_catalog | pg_class | 1259
(1 row)
--根據oid找到檔案
[postgres@node3 data]$ find . -name '1259*'
./base/1/1259
./base/1/1259_vm
./base/1/1259_fsm
./base/13543/1259
./base/13543/1259_vm
./base/13543/1259_fsm
./base/13542/1259
./base/13542/1259_vm
./base/13542/1259_fsm
./base/32771/1259
./base/32771/1259_vm
./base/32771/1259_fsm
結果:
- 在邏輯結構上;同例項下每個資料庫的表是在存放在同庫名的catalog下。
- 在物理結構上;同例項下每個資料庫的pg_class對應的資料檔案也是獨立存放的。
結論
- 在PG中;同例項下每個資料庫是完全獨立;表是在存放在同庫名的catalog下;例如Postgres資料庫的表存放在Postgres的catalog下,可以把catalog理解為database。同時物理結構是也是獨立存放的
- 每個 database 建立時;會預設為庫建立pg_catalog/information_schema
最後,前面的疑問“PostgreSQL例項中資料庫之間的關係,以及資料庫和物件的關係”,應該很好解釋清楚。
參考文獻
https://www.postgresql.org/docs/current/catalogs.html
https://www.postgresql.org/docs/current/infoschema-schema.html