iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 4
3
再探Postgresql Catalog
-----

pg_catalog schema 底下的 table, 也是定義在 pg_catalog 裡的 pg_class

可以參考 https://docs.postgresql.tw/internals/system-catalogs/pg_class#table-52-11-pg_class-columns

所以我們可以用以下 SQL Command

select *
  from pg_catalog.pg_class
 where oid = 'pg_catalog.pg_class'::regclass;

或是

select *
  from pg_catalog.pg_class
 where relname = 'pg_class';

都可以查到以下的結果

+-[ RECORD 1 ]--------+-----------------------------------------+
| relname             | pg_class                                |
| relnamespace        | 11                                      |
| reltype             | 83                                      |
| reloftype           | 0                                       |
| relowner            | 10                                      |
| relam               | 0                                       |
| relfilenode         | 0                                       |
| reltablespace       | 0                                       |
| relpages            | 12                                      |
| reltuples           | 342                                     |
| relallvisible       | 12                                      |
| reltoastrelid       | 0                                       |
| relhasindex         | t                                       |
| relisshared         | f                                       |
| relpersistence      | p                                       |
| relkind             | r                                       |
| relnatts            | 33                                      |
....


可以使用 psql metacommand 來查看

[miku]# \d pg_catalog.pg_class
                      Table "pg_catalog.pg_class"
+---------------------+--------------+-----------+----------+---------+
|       Column        |     Type     | Collation | Nullable | Default |
+---------------------+--------------+-----------+----------+---------+
| relname             | name         |           | not null |         |
| relnamespace        | oid          |           | not null |         |
| reltype             | oid          |           | not null |         |
| reloftype           | oid          |           | not null |         |
| relowner            | oid          |           | not null |         |
| relam               | oid          |           | not null |         |
| relfilenode         | oid          |           | not null |         |
| reltablespace       | oid          |           | not null |         |
| relpages            | integer      |           | not null |         |
| reltuples           | real         |           | not null |         |
| relallvisible       | integer      |           | not null |         |
| reltoastrelid       | oid          |           | not null |         |
| relhasindex         | boolean      |           | not null |         |
| relisshared         | boolean      |           | not null |         |
| relpersistence      | "char"       |           | not null |         |
| relkind             | "char"       |           | not null |         |
| relnatts            | smallint     |           | not null |         |
| relchecks           | smallint     |           | not null |         |
| relhasoids          | boolean      |           | not null |         |
| relhasrules         | boolean      |           | not null |         |
| relhastriggers      | boolean      |           | not null |         |
| relhassubclass      | boolean      |           | not null |         |
| relrowsecurity      | boolean      |           | not null |         |
| relforcerowsecurity | boolean      |           | not null |         |
| relispopulated      | boolean      |           | not null |         |
| relreplident        | "char"       |           | not null |         |
| relispartition      | boolean      |           | not null |         |
| relrewrite          | oid          |           | not null |         |
| relfrozenxid        | xid          |           | not null |         |
| relminmxid          | xid          |           | not null |         |
| relacl              | aclitem[]    |           |          |         |
| reloptions          | text[]       |           |          |         |
| relpartbound        | pg_node_tree |           |          |         |
+---------------------+--------------+-----------+----------+---------+
Indexes:
    "pg_class_oid_index" UNIQUE, btree (oid)
    "pg_class_relname_nsp_index" UNIQUE, btree (relname, relnamespace)
    "pg_class_tblspc_relfilenode_index" btree (reltablespace, relfilenode)

---
要查看是在哪個 schema (namespace),可以跟 pg_namespace join

select n.nspname
  from pg_catalog.pg_class c
  join pg_catalog.pg_namespace n
    on c.relnamespace = n.oid
 where c.relname = 'pg_class';

+------------+
|  nspname   |
+------------+
| pg_catalog |
+------------+

或是直接轉型

select relnamespace
     , relnamespace::regnamespace
  from pg_catalog.pg_class
 where relname = 'pg_class';

+--------------+--------------+
| relnamespace | relnamespace |
+--------------+--------------+
|           11 | pg_catalog   |
+--------------+--------------+

因為 relnamespace 是 oid.
請參考
https://docs.postgresql.tw/the-sql-language/data-types/8.18.-zhi-biao-xing-bie

所以可以用直接轉型的方法,Postgresql 是 物件關聯式資料庫,由此可以體會到.
請參考:
https://www.postgresql.org/docs/current/intro-whatis.html

PostgreSQL is an object-relational database management system (ORDBMS) based on POSTGRES, Version 4.2.


接著我們來查看是否有不屬於 pg_catalog 的物件

select relnamespace::regnamespace
     , count(*)
  from pg_catalog.pg_class
 where relnamespace::regnamespace::text <> 'pg_catalog'
 group by rollup(relnamespace::regnamespace)
 order by 1; 
+--------------------+-------+
|    relnamespace    | count |
+--------------------+-------+
| pg_toast           |    54 |
| public             |     1 |
| information_schema |    67 |
| miku               |    11 |
| geolite            |    11 |
| oracle             |    11 |
| dbms_pipe          |     1 |
| utl_file           |     1 |
| ¤                  |   157 |
+--------------------+-------+
(9 rows)

可以觀察到,我使用了  ::text 轉型之後來比較,並且用 rollup 來取得總計.

接著我們來看 pg_class 有多少物件及佔用空間

select c.relkind
     , count(c.*)
  from pg_catalog.pg_class c
     , pg_catalog.pg_namespace n
 where n.nspname = 'pg_catalog'
   and c.relnamespace = n.oid
 group by rollup (c.relkind)
 order by 1;

+---------+-------+
| relkind | count |
+---------+-------+
| i       |   116 |
| r       |    62 |
| v       |    59 |
| ¤       |   237 |
+---------+-------+
(4 rows)


r: Relations (ordinary tables)
v: Views
i: Indexes

select pg_size_pretty(sum(
       pg_total_relation_size(c.oid))) as curt_size
  from pg_catalog.pg_class c
     , pg_catalog.pg_namespace n
 where n.nspname = 'pg_catalog'
   and c.relnamespace = n.oid;
+-----------+
| curt_size |
+-----------+
| 14 MB     |
+-----------+
(1 row)


物件數量及容量隨著每個 Postgresql 新增或刪除物件而有所差異.
故當你實際查詢時,數字與的我的例子不同時,是正常的.

透過上面的查詢可以看到 pg_catalog 中含有 59 個 view.

觀察以下兩個query:

select schemaname
     , tablename
     , tableowner
  from pg_catalog.pg_tables -- 實際上是view 
 where schemaname = 'pg_catalog'
   and tablename = 'pg_class';
  
+------------+-----------+------------+
| schemaname | tablename | tableowner |
+------------+-----------+------------+
| pg_catalog | pg_class  | bunko666   | -- 一般owner會是postgres
+------------+-----------+------------+

select c.relnamespace
     , c.relname
     , c.relowner
  from pg_catalog.pg_class c -- table
     , pg_catalog.pg_namespace n
 where c.relname = 'pg_class'
   and n.nspname = 'pg_catalog'
   and c.relnamespace = n.oid;
+--------------+----------+----------+
| relnamespace | relname  | relowner |
+--------------+----------+----------+
|           11 | pg_class |       10 |
+--------------+----------+----------+
(1 row)


來看一下 pg_tables 的定義
\d+ pg_catalog.pg_tables
               View "pg_catalog.pg_tables"
+-------------+---------+-----------+----------+---------+
|   Column    |  Type   | Collation | Nullable | Default |
+-------------+---------+-----------+----------+---------+
| schemaname  | name    |           |          |         |
| tablename   | name    |           |          |         |
| tableowner  | name    |           |          |         |
| tablespace  | name    |           |          |         |
| hasindexes  | boolean |           |          |         |
| hasrules    | boolean |           |          |         |
| hastriggers | boolean |           |          |         |
| rowsecurity | boolean |           |          |         |
+-------------+---------+-----------+----------+---------+

View definition:
 SELECT n.nspname AS schemaname,
    c.relname AS tablename,
    pg_get_userbyid(c.relowner) AS tableowner,
    t.spcname AS tablespace,
    c.relhasindex AS hasindexes,
    c.relhasrules AS hasrules,
    c.relhastriggers AS hastriggers,
    c.relrowsecurity AS rowsecurity
   FROM pg_class c
     LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
     LEFT JOIN pg_tablespace t ON t.oid = c.reltablespace
  WHERE c.relkind = ANY (ARRAY['r'::"char", 'p'::"char"]);
  
  
可以觀察到 一般 table 與 partition table 都可以透過 pg_tables 這個 view
來方便查詢.顯示的資料也較為明晰,無需對基礎表有深入了解. view 的用處在此可見一斑.
 

pg_catalog 中物件的相關描述,該如何查詢.
我們先來看看有沒有 description 之類的名字

select c.oid
     , c.oid::regclass
  from pg_catalog.pg_class c
     , pg_catalog.pg_namespace n
 where n.nspname = 'pg_catalog'
   and c.relnamespace = n.oid
   and c.oid::regclass::text like '%description';
+------+------------------+
| oid  |       oid        |
+------+------------------+
| 2609 | pg_description   |
| 2396 | pg_shdescription |
+------+------------------+
(2 rows)

發現有 description的tables

\d pg_description
            Table "pg_catalog.pg_description"
+-------------+---------+-----------+----------+---------+
|   Column    |  Type   | Collation | Nullable | Default |
+-------------+---------+-----------+----------+---------+
| objoid      | oid     |           | not null |         |
| classoid    | oid     |           | not null |         |
| objsubid    | integer |           | not null |         |
| description | text    |           | not null |         |
+-------------+---------+-----------+----------+---------+
Indexes:
    "pg_description_o_c_o_index" UNIQUE, btree (objoid, classoid, objsubid)

一般我們查看 pg_description 

select objoid
     , classoid::regclass
     , description
  from pg_catalog.pg_description
 order by objoid
 limit 10;
+--------+--------------+-----------------------------------------------+
| objoid |   classoid   |                  description                  |
+--------+--------------+-----------------------------------------------+
|     11 | pg_namespace | system catalog schema                         |
|     12 | pg_language  | built-in functions                            |
|     13 | pg_language  | dynamically-loaded C functions                |
|     14 | pg_language  | SQL-language functions                        |
|     15 | pg_operator  | equal                                         |
|     16 | pg_type      | boolean, 'true'/'false'                       |
|     17 | pg_type      | variable-length string, binary values escaped |
|     18 | pg_type      | single character                              |
|     19 | pg_type      | 63-byte type for storing system identifiers   |
|     20 | pg_type      | ~18 digit integer, 8-byte storage             |
+--------+--------------+-----------------------------------------------+
(10 rows)

可以觀察到 Postgresql 的物件,非常精彩.

但是關於 catalog本身的描述呢??

SELECT count(d.*)
  FROM pg_catalog.pg_description d
     , pg_catalog.pg_class c
     , pg_catalog.pg_namespace n
 WHERE d.objoid = c.oid
   AND c.relnamespace = n.oid
   AND n.nspname = 'pg_catalog';

+-------+
| count |
+-------+
|     0 | -- 殘念!
+-------+

但是別擔心,生命會找到出路的.明天我們接著繼續探討.


上一篇
Postgresql 系統資訊schema pg_catalog 初步探討
下一篇
三探 Postgresql Catalog
系列文
以Postgresql為主,聊聊資料庫.30

1 則留言

我要留言

立即登入留言