Книга Егора Рогова «PostgreSQL 14 изнутри» в прошлом 2022 году. Я прочитал её черновики и решил еще летом 2022 года эту книгу прочитать. Потом вышла следующая версия, по 15-му Постгресу. Но и её я всё не читаю от начала до конца — только какие-то части.
Решил еще раз прочитать сделать еще одну попытку прочитать эту книгу всю целиком. Я хочу её прочитать не торопясь, проверяя некоторые моменты. Предлагаю читать книгу вместе.
Далее буду периодически публиковать очередные порции «прочитанного» материала — какие-то детали и эксперименты с материалом книги. Буду указывать проработанные страницы книги.
Так что мои статьи — лишь дополнение, основной материал — в книге.
Начну читать вот эту версию: PostgreSQL 15 изнутри. — М.: ДМК Пресс, 2023. — 662 с. Но уже скоро должна, я надеюсь, выйти PostgreSQL 16 изнутри, так что переключусь на неё. Наверное, первые (обзорные) страницы не особенно поменяются, так что ничего страшного не будет. Но, если всё-же будут какие-то изменения — дополню мои вышедшие статьи.
# SELECT version(); version ----------------------------------------------------------------------------------------------------------- PostgreSQL 15.4 (Ubuntu 15.4-2.pgdg23.04+1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 12.3.0-1ubuntu1~23.04) 12.3.0, 64-bit (1 row)
Сегодня рассмотрю несколько разделов:
Каждый из этих разделов далее в книге рассматривается более подробно, так что и я в данной статье лишь немного на них посмотрю.
А вы знали что утилита InitDB раньше была скриптом?
#!/bin/sh #------------------------------------------------------------------------- # # initdb.sh-- # Create (initialize) a Postgres database system. # # A database system is a collection of Postgres databases all managed # by the same postmaster. # # To create the database system, we create the directory that contains # all its data, create the files that hold the global classes, create # a few other control files for it, and create one database: the # template database.
Можно посмотреть, например, версию 6.4 в гитехабе — там был initdb.sh-скрипт. А в версии 8.0 — уже initdb.c.
В 2003 году переписали на Си. Можно посмотреть подробнее коммит:
git log 279598bb713829c6d718015c05bb2679e672bdf0
Начало там вот такое:
commit 279598bb713829c6d718015c05bb2679e672bdf0
Author: Bruce Momjian <bruce@momjian.us>
Date: Mon Nov 10 22:51:16 2003 +0000
Add C version of initdb, from Andrew Dunstan.
This is his original version with a binary rmdir() we might need in the
future.
I will commit an update version with cleanups shortly.
А список баз данных можно посмотреть запросом:
SELECT
d.datname as "Name",
pg_catalog.pg_get_userbyid(d.datdba) as "Owner",
pg_catalog.pg_encoding_to_char(d.encoding) as "Encoding",
CASE d.datlocprovider WHEN 'c' THEN 'libc' WHEN 'i' THEN 'icu' END AS "Locale Provider",
d.datcollate as "Collate",
d.datctype as "Ctype",
d.daticulocale as "ICU Locale",
NULL as "ICU Rules",
pg_catalog.array_to_string(d.datacl, E'\n') AS "Access privileges"
FROM pg_catalog.pg_database d
ORDER BY 1;
Name | Owner | Encoding | Locale Provider | Collate | Ctype | ICU Locale | ICU Rules | Access privileges
-----------+----------+----------+-----------------+-------------+-------------+------------+-----------+-----------------------
pavel | pavel | UTF8 | libc | en_US.UTF-8 | en_US.UTF-8 | | |
postgres | postgres | UTF8 | libc | en_US.UTF-8 | en_US.UTF-8 | | |
template0 | postgres | UTF8 | libc | en_US.UTF-8 | en_US.UTF-8 | | | =c/postgres +
| | | | | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | libc | en_US.UTF-8 | en_US.UTF-8 | | | =c/postgres +
| | | | | | | | postgres=CTc/postgres
(4 rows)
Общие для всего кластера объекты хранятся без указания какой-то явной таблицы:
-- Есть указание БД
SELECT pg_relation_filepath('t_toast');
pg_relation_filepath
----------------------
base/16390/16398
(1 row)
-- Нет указания БД
SELECT pg_relation_filepath('pg_database');
pg_relation_filepath
----------------------
global/1262
(1 row)
А еще можно посмотреть на представление pg_stat_database:
Представление pg_stat_database содержит по одной строке со статистикой уровня базы данных для каждой базы кластера, и ещё одну для общих объектов
SELECT * FROM pg_stat_database where datid = 0\gx
Наверное, этот id=0 как раз и подразумевался под «фиктивной бд».
SELECT datid, datname FROM pg_stat_database;
Перечень объектов системного каталога можно найти в документации.
И SQL-запросами. Либо запросом к схеме pg_catalog таблице pg_class в ней:
SELECT n.nspname as "Schema",
c.relname as "Name"
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
AND n.nspname = 'pg_catalog'
ORDER BY 1,2;
Либо запросом к схеме pg_catalog таблице tables в ней:
SELECT table_schema as "Schema", table_name as "Name" FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_schema = 'pg_catalog' ORDER BY 1,2;
Список схем можно посмотреть и таким запросом:
SELECT n.nspname AS "Name",
pg_catalog.pg_get_userbyid(n.nspowner) AS "Owner",
pg_catalog.array_to_string(n.nspacl, E'\n') AS "Access privileges"
FROM pg_catalog.pg_namespace n
ORDER BY 1;
Name | Owner | Access privileges
--------------------+-------------------+----------------------------------------
information_schema | postgres | postgres=UC/postgres +
| | =U/postgres
pg_catalog | postgres | postgres=UC/postgres +
| | =U/postgres
pg_toast | postgres |
public | pg_database_owner | pg_database_owner=UC/pg_database_owner+
| | =U/pg_database_owner
(4 rows)
Можно обратить внимание на предопределённую роль pg_database_owner. В документации пишут так:
Единственным членом роли pg_database_owner неявным образом является владелец текущей базы данных. Как и любая другая роль, она может владеть объектами или получать права доступа. Следовательно, права, данные роли pg_database_owner в базе-шаблоне, приобретёт владелец каждой базы, созданной из данного шаблона. Роль pg_database_owner не может быть членом какой-либо роли, и в неё не могут быть явно включены члены. Изначально эта роль владеет схемой public, то есть владелец базы данных управляет использованием данной схемы в своей базе.
SQL-запрос для просмотра списка табличных пространств:
SELECT spcname AS "Name",
pg_catalog.pg_get_userbyid(spcowner) AS "Owner",
pg_catalog.pg_size_pretty(pg_catalog.pg_tablespace_size(oid)) AS "Size"
FROM pg_catalog.pg_tablespace
ORDER BY 1;
Name | Owner | Size
------------+----------+--------
pg_default | postgres | 29 MB
pg_global | postgres | 555 kB
(2 rows)
Это предопределённые табличные пространства, пользовательских я не создавал — оставил это для экспериментов на попозже.
Таблица системного каталога для отношений изначально называлась pg_relation, но довольно скоро, на волне увлечения объектной ориентированностью, ее переименовали в привычный нам сейчас pg_class. Однако столбцы этой таблицы попрежнему имеют префикс rel.
Есть даже переписка этого года по этому поводу: Obsolete reference to pg_relation in comment
В гитхабе можно посмотрел Release_1_0_3, там уже есть файл pg_class, но в нём есть комментарий:
* NOTES * ``pg_relation'' is being replaced by ``pg_class''. currently * we are only changing the name in the catalogs but someday the * code will be changed too. -cim 2/26/90 * [it finally happens. -ay 11/5/94]
А поля начинаются с rel, не с class 🙂
\d pg_class
Table "pg_catalog.pg_class"
Column | Type | Collation | Nullable | Default
---------------------+--------------+-----------+----------+---------
oid | oid | | not null |
relname | name | | not null |
relnamespace | oid | | not null |
reltype | oid | | not null |
В одной из работ он даже ввел понятие «упорядоченного отношения» (ordered relation) для таблицы, в которой порядок строк задается индексом.
Наверное, вот эта работа: Document Processing in a Relational Database System, и в ней — раздел 3. ORDERED RELATIONS.
Представления не содержат данных — проверим:
CREATE VIEW v_one AS SELECT 1;
CREATE VIEW
SELECT pg_relation_filepath('v_one');
pg_relation_filepath
----------------------
(1 row)
Действительно — адреса файла нет.
А у материализованного представления — есть:
CREATE MATERIALIZED VIEW v_one_m AS SELECT 1;
SELECT 1
SELECT pg_relation_filepath('v_one_m');
pg_relation_filepath
----------------------
base/16390/16403
(1 row)
У обычных таблиц тоже:
CREATE TABLE t (id integer);
CREATE TABLE
SELECT pg_relation_filepath('t');
pg_relation_filepath
----------------------
base/16390/16395
(1 row)
Слои:
- Основной слой (main fork, _2, _3 и тд)
- Слой инициализации (init fork, _init)
- Карта свободного пространства (free space map, _fsm)
- Карта видимости (visibility map, _vm)
Посмотрим размер страницы block_size:
SHOW block_size; block_size ------------ 8192 (1 row)
Надо будет попробовать с измененным размером страницы ./configure —with-blocksize собрать, поэкспериментировать.
The Oversized Attributes Storage Technique.
Решил посмотреть кто придумал такую технику. В директории /postgres/src/backend/access/heap нужно переключиться на ту же 8-ю версию и посмотреть историю изменений файла tuptoaster.c (потому что с некоторой версии эта функциональность находится в файле heaptoast.c):
git log postgres/src/backend/access/heap/tuptoaster.c
И пролистываем в самый низ списка:
commit e2aef4969450da69bc759e19f62a2d6caec4a3d9
Author: Jan Wieck <JanWieck@Yahoo.com>
Date: Tue Dec 21 00:06:44 1999 +0000
Added empty TOASTER files and corrected some minor glitches
in regression tests.
Jan
Для бо́льшей детализации можно посмотреть сам коммит:
git show e2aef4969450da69bc759e19f62a2d6caec4a3d9
Там много строк, не буду приводить содержимое.
Проверим как работает TOAST:
CREATE TABLE t_toast (id1 integer, id2 numeric, id3 text, id4 json);
# \d+ t_toast
Table "public.t_toast"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
--------+---------+-----------+----------+---------+----------+-------------+--------------+-------------
id1 | integer | | | | plain | | |
id2 | numeric | | | | main | | |
id3 | text | | | | extended | | |
id4 | json | | | | extended | | |
Access method: heap
Параметр хранения TOAST_TUPLE_TARGET (который по умолчанию 2000 байт) можно задавать на уровне таблиц с помощью команды:
ALTER TABLE t_toast SET (toast_tuple_target = 1000);
\d+ t_toast
Table "public.t_toast"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
--------+---------+-----------+----------+---------+----------+-------------+--------------+-------------
id1 | integer | | | | plain | | |
id2 | numeric | | | | main | | |
id3 | text | | | | extended | | |
id4 | json | | | | extended | | |
Access method: heap
Options: toast_tuple_target=1000
Либо можно параметры хранения посмотреть SQL-запросам:
SELECT pg_catalog.array_to_string(c.reloptions || array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)
LEFT JOIN pg_catalog.pg_am am ON (c.relam = am.oid)
WHERE c.oid = (select oid from pg_class where relname = 't_toast');
array_to_string
-------------------------
toast_tuple_target=1000
(1 row)
Далее продолжим с раздела 1.2. Процессы и память.
Leave a Reply