Книга Егора Рогова «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