A PostgreSQL instance (or cluster) can contain many databases, three of them (template0, template1 and postgres) are there by default. Over the last years we trained many people on PostgreSQL Essentials and there have been mainly two points that needed more clarification when it comes to catalogs and the postgres default database:
- Does the postgres default database define the catalog and somehow is the master database?
- What exactly is in the global catalog?
In this post we’ll look into both points and I hope to make it more clear what the shared/global catalog contains, and that the postgres default database is not a master database and it does not define the postgres catalog.
For the first point (is the default postgres database a master database and does it define the catalog?) the answer can quite easily be given. The default postgres database is there for only one reason: Because most client utilities assume it is there, and by default connect into that database. But this does not mean, that the default postgres is any special, you can go well ahead and drop it:
postgres=# \l List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -----------+----------+----------+-------------+-------------+----------------------- postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres + | | | | | postgres=CTc/postgres (3 rows) postgres=# \c template1 You are now connected to database "template1" as user "postgres". template1=# drop database postgres; DROP DATABASE template1=# \l List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -----------+----------+----------+-------------+-------------+----------------------- template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres + | | | | | postgres=CTc/postgres (2 rows) template1=#
We even have customers which do that by default. The default postgres database is nothing special and initially it is exactly the same as template1. You can easily re-create, it if you want:
template1=# create database postgres; CREATE DATABASE template1=# \l List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -----------+----------+----------+-------------+-------------+----------------------- postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres + | | | | | postgres=CTc/postgres (3 rows)
This answers the first question: The default postgres database is not a master database and it does not define the PostgreSQL catalog. Again, check here if you want to have more details about the three default databases.
The second question can be answered easily as well: What exactly is in the global/shared catalog? Most of the PostgreSQL catalog tables are per database, such as pg_tables:
postgres=# \d 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 | | |
All these catalog tables and views are in a system schema called “pg_catalog”. This schema is not listed by default when you use the “\dn” shortcut in psql:
postgres=# \dn List of schemas Name | Owner --------+---------- public | postgres (1 row)
You need to add “S” for system, to list the system schemas:
postgres=# \dnS List of schemas Name | Owner --------------------+---------- information_schema | postgres pg_catalog | postgres pg_toast | postgres public | postgres (4 rows)
Some catalog tables/views are global to the cluster/instance and are not per database. The obvious ones are users/roles and tablespaces. None of them are per database as users/roles can have access to various databases and various databases can store relations in the same tablespace. The question now is: How can I know if a catalog table/view is global or per database? Even global catalog tables/views are listed in the local catalog schema:
postgres=# \d pg_catalog.pg_roles View "pg_catalog.pg_roles" Column | Type | Collation | Nullable | Default ----------------+--------------------------+-----------+----------+--------- rolname | name | | | rolsuper | boolean | | | rolinherit | boolean | | | rolcreaterole | boolean | | | rolcreatedb | boolean | | | rolcanlogin | boolean | | | rolreplication | boolean | | | rolconnlimit | integer | | | rolpassword | text | | | rolvaliduntil | timestamp with time zone | | | rolbypassrls | boolean | | | rolconfig | text[] | C | | oid | oid | | |
By only looking in the catalog schema we can not answer that question. What we can do, however, is to look at the data directory ($PGDATA). The databases are in “base” and the global/shared catalog is in “global”:
postgres@centos8pg:/home/postgres/ [pgdev] cd $PGDATA postgres@centos8pg:/u02/pgdata/DEV/ [pgdev] ls -l | egrep "base|global" drwx------. 6 postgres postgres 58 Nov 21 09:50 base drwx------. 2 postgres postgres 4096 Nov 21 09:48 global
When we look into the “global” directory we’ll see a number of OIDs (object identifiers), this is how PostgreSQL internally is referencing the relations:
postgres@centos8pg:/u02/pgdata/DEV/ [pgdev] ls -l global/ total 564 -rw-------. 1 postgres postgres 8192 Nov 21 03:52 1213 -rw-------. 1 postgres postgres 24576 Nov 20 22:52 1213_fsm -rw-------. 1 postgres postgres 8192 Nov 21 03:53 1213_vm -rw-------. 1 postgres postgres 8192 Nov 20 22:52 1214 -rw-------. 1 postgres postgres 24576 Nov 20 22:52 1214_fsm -rw-------. 1 postgres postgres 8192 Nov 20 22:52 1214_vm -rw-------. 1 postgres postgres 16384 Nov 20 22:52 1232 -rw-------. 1 postgres postgres 16384 Nov 20 22:52 1233 -rw-------. 1 postgres postgres 8192 Nov 20 22:57 1260 -rw-------. 1 postgres postgres 24576 Nov 20 22:52 1260_fsm -rw-------. 1 postgres postgres 8192 Nov 20 22:52 1260_vm ...
Each of these OIDs is one relation of the global/shared catalog. As we are not interested in the visibility maps and free space maps let’s exclude them, and only list the unique OIDs:
postgres@centos8pg:/u02/pgdata/DEV/ [pgdev] ls -l global/ | awk -F " " '{print $9}' | egrep "^[0-9]" | egrep -v "fsm|vm" 1213 1214 1232 1233 1260 1261 1262 2396 2397 2671 2672 2676 2677 2694 2695 2697 2698 2846 2847 2964 2965 2966 2967 3592 3593 4060 4061 4175 4176 4177 4178 4181 4182 4183 4184 4185 4186 6000 6001 6002 6100 6114 6115
These are the relations in the global/shared catalog. For translating these OIDs into human readable names there is oid2name. Without any additional parameters oid2name will give you the name of the databases listed in the “base” directory:
postgres@centos8pg:/u02/pgdata/DEV/ [pgdev] oid2name All databases: Oid Database Name Tablespace ---------------------------------- 24616 postgres pg_default 12905 template0 pg_default 1 template1 pg_default
We can also pass the OIDs of the shared/global catalog to oid2name and the result will answer the second question: What, exactly, is in the global/shared catalog?
postgres@centos8pg:/u02/pgdata/DEV/ [pgdev] for i in `ls -l global/ | awk -F " " '{print $9}' | egrep "^[0-9]" | egrep -v "fsm|vm"`; do oid2name -x -S -q -o $i; done | grep -v "index" 1213 pg_tablespace 1213 pg_catalog pg_global 1214 pg_shdepend 1214 pg_catalog pg_global 1260 pg_authid 1260 pg_catalog pg_global 1261 pg_auth_members 1261 pg_catalog pg_global 1262 pg_database 1262 pg_catalog pg_global 2396 pg_shdescription 2396 pg_catalog pg_global 2846 pg_toast_2396 2846 pg_toast pg_global 2964 pg_db_role_setting 2964 pg_catalog pg_global 2966 pg_toast_2964 2966 pg_toast pg_global 3592 pg_shseclabel 3592 pg_catalog pg_global 4060 pg_toast_3592 4060 pg_toast pg_global 4175 pg_toast_1260 4175 pg_toast pg_global 4177 pg_toast_1262 4177 pg_toast pg_global 4181 pg_toast_6000 4181 pg_toast pg_global 4183 pg_toast_6100 4183 pg_toast pg_global 4185 pg_toast_1213 4185 pg_toast pg_global 6000 pg_replication_origin 6000 pg_catalog pg_global 6100 pg_subscription 6100 pg_catalog pg_global
Here is the answer (excluding the indexes). If we exclude the toast tables as well, you’ll notice that not many catalog tables/views are in the global/shared catalog:
postgres@centos8pg:/u02/pgdata/DEV/ [pgdev] for i in `ls -l global/ | awk -F " " '{print $9}' | egrep "^[0-9]" | egrep -v "fsm|vm"`; do oid2name -x -S -q -o $i; done | egrep -v "index|toast" 1213 pg_tablespace 1213 pg_catalog pg_global 1214 pg_shdepend 1214 pg_catalog pg_global 1260 pg_authid 1260 pg_catalog pg_global 1261 pg_auth_members 1261 pg_catalog pg_global 1262 pg_database 1262 pg_catalog pg_global 2396 pg_shdescription 2396 pg_catalog pg_global 2964 pg_db_role_setting 2964 pg_catalog pg_global 3592 pg_shseclabel 3592 pg_catalog pg_global 6000 pg_replication_origin 6000 pg_catalog pg_global 6100 pg_subscription 6100 pg_catalog pg_global
That’s it, hope it helps.
Cet article The PostgreSQL shared/global catalog est apparu en premier sur Blog dbi services.