An open API service indexing awesome lists of open source software.

https://github.com/hyperion-cs/pgsql_faq

:elephant: PostgreSQL: Ответы на часто задаваемые вопросы начинающих DBA / FAQ for DBA beginners.
https://github.com/hyperion-cs/pgsql_faq

beginner dba dbms faq pgsql postgresql

Last synced: 16 days ago
JSON representation

:elephant: PostgreSQL: Ответы на часто задаваемые вопросы начинающих DBA / FAQ for DBA beginners.

Awesome Lists containing this project

README

          

# :elephant: PostgreSQL – FAQ

Ответы на часто задаваемые вопросы / FAQ.

## Введение

:exclamation: В первую очередь, мы должны уметь думать **самостоятельно**.
В особенности, это касается проблем, которые у вас возникают
— сначала тщательно и усердно попытайтесь [нагуглить](https://www.google.com/) решение, и только в случае неудачи задавайте вопросы (_как это делать правильно — см. ниже_).

Уважайте время и труд других участников сообщества, общайтесь исключительно в вежливой манере.
Это первостепенные и необходимые условия для того, чтобы приумножать свои навыки и расти как профессионал.

## Оглавление / Table of Contents

1. [Сообщество](#1-community)
2. [Вопросы](#2-questions)

2.1. [Не могу подсоединиться к PostgreSQL. Что делать?](#2.1-connection-problem)

2.2. [Получаю ошибку что имя таблицы/колонки/etc неверное, хотя это не так. В чем дело?](#2.2-name-does-not-exist)

2.3. [Как публиковать SQL запросы, определения функций, выводы команд вспомогательных утилит и прочую текстовую информацию при запросе помощи у сообщества?](#2.3-data-publication)

2.4. [У меня медленно работает SQL запрос и я хочу попросить помощи у сообщества. Какую информацию мне необходимо предоставить?](#2.4-slow-query)

2.5. [У меня не получается написать SQL запрос/etc и/или я получаю ошибки. Какую информацию мне необходимо предоставить для получения помощи от сообщества?](#2.5-invalid-query)

2.6. [В каком стиле писать код и идентификаторы в PostgreSQL?](#2.6-coding-style)

2.7. [Секционирование (партиционирование)](#2.7-partitioning)

- 2.7.1. [Какие убедительные причины (не)использования секционирования?](#2.7.1-partitioning-reasons-for-use)

- 2.7.2. [Какие плюсы и минусы есть у секционирования?](#2.7.2-partitioning-pros-and-cons)

- 2.7.3. [Какие нюансы есть при работе с секционированием?](#2.7.3-partitioning-nuances)

2.8. [База/таблица весит больше чем я ожидаю, что делать?](#2.8-fat-dbms)

2.9. [Как работает тип _timestamp with time zone_?](#2.9-timestamptz)

2.10. [Что не так со звездочками _(*)_?](#2.10-why-asterisk-is-bad)

2.11. [Утилита pg_dump создает бэкапы?](#2.11-pgdump_is_not_backup)

3. [Книги/курсы](#3-learning)
4. [Полезные ссылки](#4-links)
5. [Переводы / Translations](translations)

5.1. [English](translations/ENG.md)

## [1.](#1-community) Сообщество :family_man_woman_girl_boy:

У PostgreSQL прекрасное сообщество, которое обладает, в том числе, заметным свойством толерантности к начинающим участникам.
Среди основных точек входа стоит отметить следующие:

1. [Чат русскоязычного сообщества PostgreSQL в Telegram](https://t.me/pgsql);
2. [PGDay.ru](https://pgday.ru/) - Ежегодная конференция по PostgreSQL (Санкт-Петербург);
3. [PGConf.ru](https://pgconf.ru/) - Ежегодная конференция по PostgreSQL (Москва).

## [2.](#2-questions) Вопросы :interrobang:

### [2.1.](#2.1-connection-problem) Не могу подсоединиться к PostgreSQL. Что делать?

Пожалуй, это наиболее частый вопрос у начинающих пользователей PostgreSQL, ежедневно звучащий в информационной среде сообщества.
Как правило, они получают ошибки, содержащие ключевые слова `Connection refused` или `Connection ... failed`. Например:
```
error: connection to server at "localhost", port 5432 failed: Connection refused
```
или (в случае попытки подключения через [unix domain socket](https://en.wikipedia.org/wiki/Unix_domain_socket)):
```
error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory
Is the server running locally and accepting connections on that socket?
```

Следует провести диагностику проблемы поэтапно (_в настоящее время инструкция применительна только для Unix-based ОС_):

#### 2.1.1. Запущен ли основной процесс PostgreSQL?

Посмотреть, запущен ли основной процесс PostgreSQL, можно выполнив след. команду на сервере:

```bash
ps -ef | grep "postgresql.*config_file"
```

В случае, если PostgreSQL запущен, в выводе команды вы должны увидеть нечто вроде:
```bash
-D -c config_file=
```

Где `` — путь до исполняемого файла PostgreSQL,
`` — путь до директории с данными кластера,
`` — пусть до конфигурационного файла `postgresql.conf` (потребуется для дальнейшей диагностики).

В противном случае, проблема найдена: PostgreSQL не запущен.
При этом, если попытка запуска СУБД окажется неудачной — в первую очередь обратите внимание на её логи.

#### 2.1.2. Верен ли TCP-порт, открываемый сервером PostgreSQL?

Теперь необходимо убедиться, что PostgreSQL слушает нужный вам TCP-порт (если, конечно, вы не собираетесь работать только через Unix-сокеты).
Откройте конфигурационный файл `postgresql.conf` (путь до него мы определили этапом выше) и найдите параметр `port`.
Там должно быть значение необходимого вам порта, который по умолчанию равен `5432`.
В противном случае, исправьте номер порта на нужное вам значение. После применения изменений необходимо произвести рестарт PostgreSQL.

_\* В то же время, можно скорректировать значения порта непосредственно на клиенте (т.е. там, где возникла ошибка соединения)
— всё зависит от того, какой из портов вы считаете корректным._

После рестарта PostgreSQL можно удостовериться, что нужный вам порт действительно прослушивается.
Для этого можно выполнить след. команду на сервере (для порта `5432`):
```bash
ss -ln | grep ":5432"
```

В случае успеха, в выводе команды вы должны наблюдать одну или несколько строк с операцией _LISTEN_, которые показывают, что PostgreSQL действительно прослушивает порт.
В противном случае (учитывая, что шаг выше показал, что основной процесс СУБД запущен),
вероятно, вы неверно указали значение `port` либо настроена работа только через Unix-сокеты — как это исправить см. ниже.

#### 2.1.3. Верны ли адреса TCP/IP, по которым PostgreSQL принимает подключения?

Параметром в файле `postgresql.conf`, отвечающим за то, через какие [сетевые интерфейсы](https://ru.wikipedia.org/wiki/%D0%A1%D0%B5%D1%82%D0%B5%D0%B2%D0%BE%D0%B9_%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D1%84%D0%B5%D0%B9%D1%81)
PostgreSQL будет принимать соединения, является `listen_addresses`.

Если вы хотите подключиться к PostgreSQL локально (т.е. с того же сервера), подойдут значения
`127.0.0.1` (для подключения по IPv4), `::1` (для подключения по IPv6) или `localhost` (в современных ОС данное доменное имя, как правило, транслируется в `::1`. Подробнее см. [тут](https://ru.wikipedia.org/wiki/Localhost)).
Стоит отметить, что в параметре `listen_addresses`, как следует из его названия, можно указать несколько значений через запятую.
Учтите, что старые клиентские приложения, в подавляющем большинстве случаев, работают по IPv4.

Если вы хотите подключиться к PostgreSQL удаленно (т.е. с другого сервера), то необходимо принимать подключения с соотв. внешних интерфейсов.
С помощью значения `0.0.0.0` можно принимать подключения со всех адресов IPv4, а `::` — все адреса IPv6.
В то же время, если указать значение `*`, то PostgreSQL будет принимать подключения со всех имеющихся сетевых интерфейсов.

Подробнее о подключениях и аутентификации к PostgreSQL см. [тут](https://postgrespro.ru/docs/postgresql/17/runtime-config-connection#RUNTIME-CONFIG-CONNECTION-SETTINGS).
Напомним, что после применения изменений в файл `postgresql.conf` необходимо произвести рестарт PostgreSQL.

:exclamation: В случае, если вы указали PostgreSQL прослушивать внешние интерфейсы
(т.е., что-то, отличное от значений `127.0.0.1`, `::1` или `localhost` параметра `listen_addresses`),
то ваш сервер может быть доступне извне (т.е. из Интернета) и потенциально находится под угрозой.
Чтобы избежать негативных последствий, необходимо корректно настроить ваш [firewall](https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B5%D1%82%D0%B5%D0%B2%D0%BE%D0%B9_%D1%8D%D0%BA%D1%80%D0%B0%D0%BD) и файл `pg_hba.conf`. Подробнее о них см. ниже.

#### 2.1.4. Верна ли конфигурация аутентификации клиентов PostgreSQL?

Несмотря на то, что параметр `listen_addresses` в файле `postgresql.conf` настроен верно, PostgreSQL всё ещё может отвергать соединения.
Причиной может быть то, что в конфигурационном файле `pg_hba.conf` нет соответствующего разрешения.

Подробнее о файле `pg_hba.conf` см. [тут](https://postgrespro.ru/docs/postgresql/17/auth-pg-hba-conf) (включая примеры настройки).

#### 2.1.5. Верна ли конфигурация firewall?

Даже если PostgreSQL настроен верно (с точки зрения подключения клиентов), вы всё ещё можете иметь неудачные попытки подключения.
В этом случае вам необходимо обратить внимание на правильность настройки [firewall](https://en.wikipedia.org/wiki/Firewall_(computing))
(он может быть как на уровне ОС, так и на уровне ваших сетевых аппаратных/виртуальных устройств, напр., роутера).
Конкретные шаги выходят за рамки данного FAQ.

---

### [2.2.](#2.2-name-does-not-exist) Получаю ошибку что имя таблицы/колонки/etc неверное, хотя это не так. В чем дело?

В подавляющем большинстве случаев, дело в том, что имя таблицы/колонки (равно как и любого другого символьного идентификатора) содержит символы в верхнем регистре (т.е. заглавные буквы).
В то же время, по умолчанию, PostgreSQL преобразовывает указанные в запросе/команде идентификаторы в нижний регистр.
Чтобы избежать ошибки, в запросе/команде необходимо заключить идентификатор в двойные кавычки (в этом случае вышеописанное преобразование будет отключено).

Пример воспроизведения и решения проблемы:

```sql
SELECT * FROM TableName; -- error: relation "tablename" does not exist
SELECT * FROM "TableName"; -- OK
```

Обратите внимание, что идентификатор `TableName` без двойных кавычек был преобразован в `tablename`, что вызвало ошибку.

Для того, чтобы даже гипотетически избежать таких проблем, не рекомендуется использование символов верхнего регистра в идентификаторах.
Однако, это ни в коем случае не является обязательным правилом.

---

### [2.3.](#2.3-data-publication) Как публиковать SQL запросы, определения функций, выводы команд вспомогательных утилит и прочую текстовую информацию при запросе помощи у сообщества?

Прежде всего, **не используйте** скриншоты для того, чтобы показать SQL запросы (и/или их результаты), определения функций,
выводы команд вспомогательных утилит (таких, как [psql](https://postgrespro.ru/docs/postgresql/17/app-psql) и др.) и прочую текстовую информацию — это затрудняет их анализ, скорость/удобство воспроизведения проблемы и переиспользования вашего кода.
Заметно эффективнее будет публикация оных, напр., на [gist](https://gist.github.com/) или [pastebin.com](https://pastebin.com/).

При этом, если вы задаете вопрос в tg-чате и кол-во содержимого невелико, его следует опубликовать в режиме [форматирования Monospace](https://telegra.ph/markdown-07-07) непосредственно в чат, используя ` ```language syntax `, выбрав в кач-ве языка `sql` (таким образом будет достигнута подсветка синтаксиса SQL).
Как правило, этот вопрос тесно связан с п. [2.4](#2.4-slow-query) и п. [2.5](#2.5-invalid-query).

Многие участники сообщества принципиально не рассматривают скриншоты (и на это есть рациональные причины), поэтому постарайтесь оформить свой текст правильно.

---

### [2.4.](#2.4-slow-query) У меня медленно работает SQL запрос и я хочу попросить помощи у сообщества. Какую информацию мне необходимо предоставить?

Чтобы получить адекватную помощь по оптимизации запроса, необходимо немного постараться и собрать некоторые данные.

Минимальная информация для получения помощи следующая:

1. Версия PostgreSQL на сервере, где запускается запрос — можно использовать вывод `SELECT version();`
2. Непосредственно SQL запрос;
3. Вывод метакоманды `\d+` из утилиты [psql](https://postgrespro.ru/docs/postgresql/17/app-psql) для каждой используемой в запросе таблицы;
4. `EXPLAIN (ANALYZE, VERBOSE, BUFFERS, COSTS, SETTINGS, TIMING, WAL)` для запроса (подробнее об _EXPLAIN_ см. [тут](https://postgrespro.ru/docs/postgresql/17/sql-explain)).
Если ваша версия PostgreSQL ещё не поддерживает какие-то из опций _EXPLAIN_ выше, то уберите их. Когда нет возможности дождаться результата запроса, можно также убрать и опцию _ANALYZE_.

:bulb: Для автоматизации этого процесса можно воспользоваться [данным](https://gist.github.com/hyperion-cs/dc97d41e8e4f44944c876015b61f56c4) _.sql_ скриптом под утилиту `psql`.

:exclamation: Внимательно отнеситесь к тому, как [публиковать информацию](#2.3-data-publication), которая требуется для ответа на ваш вопрос.

---

### [2.5.](#2.5-invalid-query) У меня не получается написать SQL запрос/etc и/или я получаю ошибки. Какую информацию мне необходимо предоставить для получения помощи от сообщества?

1. Кратко опишите предметную область и то, что вы хотите сделать;
2. Продемонстрируйте то, что вы уже сделали. Это докажет то, что вы попытались решить проблему самостоятельно,
а также даст начальную точку для участников сообщества, которые захотят вам помочь. Если вы получаете ошибки, то их также стоит приложить к своему вопросу;
3. Выполните хотя бы один из пунктов:

3.1. Предоставьте вывод метакоманды `\d` из утилиты [psql](https://postgrespro.ru/docs/postgresql/17/app-psql) для каждой таблицы, которая будет участвовать в запросе;

3.2. Создайте тестовое окружение, которое воспроизводит ваши [таблицы](https://postgrespro.ru/docs/postgresql/17/ddl)/данные и непосредственно проблему.
Это поможет другим участникам сообщества легко и быстро приступить к изучению вашей проблемы (и, как следствие, повысит желание помогать в её решении).
Для этого следует использовать такие сервисы как [sqlize.online](https://sqlize.online/) или [db-fiddle.com](https://www.db-fiddle.com/).

:exclamation: Внимательно отнеситесь к тому, как [публиковать информацию](#2.3-data-publication),
которая требуется для ответа на ваш вопрос.

---

### [2.6.](#2.6-coding-style) В каком стиле писать код и идентификаторы в PostgreSQL?

Стоит отметить, что у сообщества нет единого мнения по данному вопросу.
Однако, настоятельно не рекомендуется использовать в идентификаторах (именах объектов) что-то, отличное от символов латинского алфавита из нижнего регистра (_a-z_), арабских цифр (_0-9_) и символа нижнего подчеркивания (\_), т.к. это потенциально может привести к техническим проблемам. В том числе использование символов из верхнего регистра (напр., _A-Z_) имеет нюансы, описанные [ранее](#2.2-name-does-not-exist). Как следует из вышесказанного, символы русского алфавита также не рекомендуются.

В остальном, это зависит исключительно от того, как принято в вашей команде и/или организации (см. [coding style](https://en.wikipedia.org/wiki/Programming_style)).
Внутри команды и/или организации важно соблюдать единый стандарт для того чтобы в дальнейшем его было легко читать/поддерживать как вам, так и вашим коллегам.

Если обратиться к примерам [официальной документации](https://www.postgresql.org/docs/) PostgreSQL (которые также имеют некоторое разночтение), то, как правило, им свойственно следующее:
1. Почти все [ключевые слова](https://postgrespro.ru/docs/postgresql/17/sql-keywords-appendix),
включая слова из [DML](https://ru.wikipedia.org/wiki/Data_Manipulation_Language) (_SELECT/INSERT/UPDATE/DELETE_),
[DDL](https://postgrespro.ru/docs/postgresql/17/ddl) (_CREATE/ALTER/DROP_),
[DCL](https://ru.wikipedia.org/wiki/Data_Control_Language) (_GRANT/REVOKE_),
а также TCL (_COMMIT/ROLLBACK/SAVEPOINT_) пишутся в верхнем регистре. Исключение составляют идентификаторы (см. ниже). Например:
```sql
SELECT * FROM table;
```
2. Идентификаторы (имена таблиц, столбцов, функций, типов и т.д.) в большинстве случаев пишутся в нижнем регистре в формате [snake_case](https://ru.wikipedia.org/wiki/Snake_case). Например:
```sql
SELECT floor(col_name) FROM table;
```

---

### [2.7.](#2.7-partitioning) Секционирование (партиционирование)

#### [2.7.1.](#2.7.1-partitioning-reasons-for-use) Какие убедительные причины (не)использования секционирования?
:white_check_mark: Когда это может быть необходимо и/или полезно:
- PostgreSQL [имеет](https://www.postgresql.org/docs/current/limits.html) некоторые жёсткие ограничения, которые касаются, в частности, и максимального размера отношения (чем является таблица) — `32 TB`. Таким образом, если объем ваших данных в таблице приближается к данному значению, то это веский повод задуматься о секционировании в самое ближайшее время;
- Если кол-во записей в таблице начинает превышать 5-10 миллиардов строк (и её размер составляет несколько _TB_ без учета индексов — в этом смысле важна средняя ширина строк в таблице), то это повод неспеша задуматься о секционировании;
- Если появилась необходимость отправлять часть данных таблицы в "холодное" (более дешевое, но менее производительное) хранилище/архив — секционирование может помочь. Это разумно в случаях, когда эти данные требуются только в режиме read-only, и сравнительно редко. Как правило, к этому приходят по экономическим причинам (в то же время, производительность системы так или иначе падает).

:x: Когда в этом нет необходимости и/или может быть вредно:
- Не стоит применять секционирование только потому что это "модно", без оглядки на объективные технические причины. Иначе, вполне вероятно, вы получите больше вреда нежели пользы;
- Если кол-во записей в таблице не превышет 5-10 миллиардов строк (а её размер не превышает несколько _TB_ без учета индексов), то, в среднем, задумываться о секционировании преждевременно — разумнее будет рассмотреть вертикальное масштабирование сервера СУБД, если необходимо. Однако, следует учитывать динамику роста кол-ва данных в таблице с течением времени (соотнося её с предполагаемым временем жизни системы);
- Если вы планируете применить секционирование, физически оставив/расположив секции на одном накопителе (диске) — в большинстве случаев это сомнительная затея. Бывают и исключения, которые частично описаны в данном FAQ.

#### [2.7.2.](#2.7.2-partitioning-pros-and-cons) Какие плюсы и минусы есть у секционирования?
:white_check_mark: Плюсы:
- Массовое удаление данных можно осуществить удаляя конкретные секции — что значительно эффективнее (в нескольких смыслах), чем аналогичный _DELETE statement_ для обычной таблицы. Очевидно, это возможно лишь в случаях, когда в этих секциях не содержится ничего кроме запланированных к удалению данных;
- Секции можно расположить на различных [tablespaces](https://www.postgresql.org/docs/current/manage-ag-tablespaces.html) или даже экземплярах PostgreSQL — используя, напр., [foreign data wrappers](https://www.postgresql.org/docs/current/postgres-fdw.html). Это открывает возможности к горизонтальному масштабированию СУБД (впрочем, это не единственный варант).

:x: Минусы:
- На каждую секцию создается **отдельный** индекс. Это, помимо прочего, может привести к замедлению запросов в `N` раз (где `N` - кол-во секций). Однако, в некоторых случаях может заметно помочь [partition pruning](https://www.postgresql.org/docs/current/ddl-partitioning.html#DDL-PARTITION-PRUNING);
- Поддерживать секционированную таблицу, так или иначе, сложнее, чем обычную.

#### [2.7.3.](#2.7.3-partitioning-nuances) Какие нюансы есть при работе с секционированием?
Представим, что вы всё-таки решили использовать секционирование. В таком случае, вам следует знать следующее:
- Не следует делать слишком большое кол-во секций (и/или которые содержат слишком мало данных). В первом приближении можно исходить из того, что `10 000` секций — это **верхний** предел, до которого секционирование работает условно-нормально. Это связано с тем, что [планировщик](https://www.postgresql.org/docs/current/planner-optimizer.html) для каждого запроса к секционированной таблице должен решить, какие секции потребуются для работы, что требует времени;
- Из коробки PostgreSQL поддерживает [декларативное](https://www.postgresql.org/docs/current/ddl-partitioning.html#DDL-PARTITIONING-DECLARATIVE) секционирование и [с использованием наследования](https://www.postgresql.org/docs/current/ddl-partitioning.html#DDL-PARTITIONING-USING-INHERITANCE), первый вариант активно развивается и является хорошей отправной точкой для погружения в данную тему. Однако, существуют и сторонние решения, которые могут помочь в этом с уклоном в горизонтальное масштабирование/шардирование (напр., [citus](https://github.com/citusdata/citus), [spqr](https://github.com/pg-sharding/spqr) и [timescaledb](https://github.com/timescale/timescaledb)).

---

### [2.8.](#2.8-fat-dbms) База/таблица весит больше чем я ожидаю, что делать?
Такое состояние может возникать по разным причинам, и не все случаи требуют вмешательства.

Рассмотрим некоторые из них:
- Вы что-то удалили из таблицы посредством [_DELETE_](https://postgrespro.ru/docs/postgresql/17/sql-delete) и ожидаете что на диске появится дополнительное свободное место, либо были обновления через [_UPDATE_](https://postgrespro.ru/docs/postgresql/17/sql-update) и таблица "распухла"?

- При удалении строк они физически **не удаляются** с диска, а лишь помечаются как удаленные;
- При обновлении строк они физически **не обновляются** "на месте", вместо этого создаются новые строки (старые же помечаются как удаленные — в этом смысле _UPDATE_ можно рассматривать как атомарный _DELETE_ + [_INSERT_](https://postgrespro.ru/docs/postgresql/17/sql-insert)). Если не менялся [_primary key_](https://postgrespro.ru/docs/postgresql/17/ddl-constraints#DDL-CONSTRAINTS-PRIMARY-KEYS) (при его наличии), то, логически, это та же самая строка;
- Нередко это штатная ситуация, когда свободное место не возвращается ОС — оно будет переиспользовано СУБД в дальнейшем;
- Эти процессы могут порождать т.н. _table bloat_ (похожим образом могут распухать и, напр., индексы). Решение этой "проблемы" можно начать со знакомства с командой [_VACUUM_](https://postgrespro.ru/docs/postgresql/17/sql-vacuum) (в т.ч. опции _FULL_) и механизма [autovacuum](https://postgrespro.ru/docs/postgresql/17/routine-vacuuming#AUTOVACUUM), но есть и более продвинутые способы.

- Когда-то был сбой в СУБД (в т.ч. неблагоприятный откат транзакции и/или аварийное завершение работы)?

- В этом случае, вероятно, могут появиться т.н. "файлы-сироты" (_probably orphaned files_). Они физически есть на диске, однако, уже не связаны логически с БД (т.е., фактически, представляют собой мусор). Вы можете выявить их (и далее, возможно, вручную удалить) с помощью [данного](https://gist.github.com/hyperion-cs/c0df0110e6fc575dc85f797af4342afe) скрипта.

:warning: Иногда вы можете быть и не в курсе, что это произошло. Таким образом, время от времени, отслеживать "сирот" не помешает.

### [2.9.](#2.9-timestamptz) Как работает тип _timestamp with time zone_?
Прежде всего, в PostgreSQL **нет** встроенного типа данных, который бы хранил временную метку вместе с часовым поясом.
И даже `timestamp with time zone` (он же `timestamptz`), несмотря на его название, этой информации не хранит. Однако, это не является проблемой.

В среднем, при _записи_ в БД значения от клиента, оно на уровне СУБД преобразуется к [UTC](https://en.wikipedia.org/wiki/Coordinated_Universal_Time), а при _запросе_ клиентом значения из БД оно преобразуется в локальное время, также на уровне СУБД (в т.ч. к метке добавляется часовой пояс в формате `+TZ` в конце строки — в этом смысле название типа _... with time zone_ себя в некоторой степени оправдывает).

Более подробно это поведение [описывается](https://postgrespro.ru/docs/postgresql/17/datatype-datetime#DATATYPE-DATETIME-INPUT-TIME-STAMPS) в документации.

:bulb: Приведение на уровне СУБД временной метки к UTC (и из него) для типа `timestamp with time zone` справедливо для случаев, когда клиент и СУБД обмениваются временными метками как строками (в подавляющем большинстве случаев это так, но иногда ответственность за приведение может взять на себя клиент). Как бы то ни было, в любом случае, вышуказанный тип не будет хранить часовой пояс (и СУБД будет полагать, что там физически хранится значение в формате UTC).

:exclamation: Во избежание путаницы, с клиента к СУБД рекомендуется передавать временную метку в виде строки где **явно** указан часовой пояс (по стандарту [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601), т.е. `YYYY-MM-DD HH:MI[:SS][.FFFFFF]+TZ`, где `[:SS]` (_кол-во секунд_) и `[.FFFFFF]` (_"дробная" часть секунды_) являются опциональными частями; пример: `2025-01-20 17:14:16.71292+03`). Это гарантирует, что приведение к UTC внутри СУБД будет выполнено корректно вне зависимости от текущей конфигурации локальной временной зоны как на сервере, так и на клиенте.

---

### [2.10.](#2.10-why-asterisk-is-bad) Что не так со звездочками (*)?
Не используйте _SELECT/RETURNING *_ кроме как для отладки. Где бы то ни было. Сразу по нескольким причинам, в т.ч.:
- Производительность — чем больше столбцов возвращает запрос, тем больше нагрузка на сеть, сериализацию данных и т.д. В некоторых случаях может и вовсе быть "лишний поход" в [TOAST](https://postgrespro.ru/docs/postgresql/17/storage-toast) за теми данными, которые на самом деле не нужны, что является достаточно дорогой операцией;
- Безопасность — при добавлении новых, в т.ч. системных/конфедициальных столбцов, в используемые в запросе таблицы, они случайно могут "протечь" туда, куда не следует (вплоть до конечного клиента в запущенных случаях);
- Предсказуемость и стабильность поведения — в общем случае непонятно, что такое "вернуть всё", особенно с течением времени (и результаты могут быть довольно неожиданными).

Например:
```sql
SELECT * FROM users; -- Плохо
SELECT id, name FROM users; -- Хорошо
```

### [2.11.](#2.11-pgdump_is_not_backup) Утилита pg_dump создает бэкапы?

Ознакомившись с [документацией](https://www.postgresql.org/docs/17/app-pgdump.html) (и не только) можно предположить, что _pg_dump_ является утилитой для создания бэкапов.
Однако, в действительности, она создает не полноценный бэкап, а лишь **логический дамп** содержимого базы данных,
на основании которого в дальнейшем можно попытаться "восстановить" состояние БД. Среди прочего:
- Восстановленные (через [pg_restore](https://postgrespro.ru/docs/postgresql/17/app-pgrestore)) объекты получают другие [OID](https://postgrespro.ru/docs/postgresql/17/datatype-oid);
- Время восстановления труднопрогнозируемо (в т.ч. при построении индексов) и в среднем _заметно дольше_, чем у подходящих инструментов;
- В ряде случаев _pg_dump_ может аварийно завершиться или выдать некорректные результаты ([пример](https://t.me/pgsql/479018));
- Интерфейс утилиты перегружен исторически устаревшими и запутанными параметрами — это может привести к неожиданным результатам.

Для создания надежных бэкапов (бинарных копий) следует использовать, напр., [pg_basebackup](https://postgrespro.ru/docs/postgresql/17/app-pgbasebackup) или иные соотв. утилиты.

## [3.](#3-learning) Книги/курсы :blue_book:
1. [Образовательные материалы](https://postgrespro.ru/education/) от компании Postgres Professional, в т.ч. (в порядке увеличения сложности):

1.1. [Postgres: первое знакомство](https://www.postgrespro.ru/education/books/introbook) (книга, [.pdf](https://edu.postgrespro.ru/introbook_v11.pdf));

1.2. [PostgreSQL. Основы языка SQL](https://postgrespro.ru/education/books/sqlprimer) (книга, [.pdf](https://edu.postgrespro.ru/sql_primer.pdf));

1.3. [PostgreSQL. Профессиональный SQL](https://postgrespro.ru/education/books/advancedsql) (книга, [.pdf](https://edu.postgrespro.ru/advanced_sql.pdf));

1.4. [Основы технологий баз данных](https://postgrespro.ru/education/university/dbtech);

1.5. [PostgreSQL изнутри](https://www.postgrespro.ru/education/books/internals) (книга, [.pdf](https://edu.postgrespro.ru/postgresql_internals-17.pdf)).

_* Стоит заметить, что материалы выше не являются рекламой — они действительно крайне достойного качества, при этом распространяются свободно._

## [4.](#4-links) Полезные ссылки :link:

1. [Документация PostgreSQL на русском языке](https://postgrespro.ru/docs/postgresql/);
2. [Вредные и/или опасные действия в PostgreSQL](https://wiki.postgresql.org/wiki/Don't_Do_This) _(eng)_;
3. [SQLize — быстрый запуск, эксперименты и обмен кодом SQL](https://sqlize.online/);
4. [SQLtest — упражнения по SQL](https://sqltest.online/ru);
5. LeetCode Database Problems — упражнения по SQL: [базовые задачи](https://leetcode.com/studyplan/top-sql-50/), [все задачи](https://leetcode.com/problem-list/database/) _(eng)_;
6. [Sql-ex.ru — упражнения по SQL](https://www.sql-ex.ru/?Lang=0);
7. [Официальный FAQ на русском языке](https://wiki.postgresql.org/wiki/FAQ/ru);
8. [Neon — туториалы по PostgreSQL, примеры использования](https://neon.tech/postgresql/tutorial) _(eng)_;
9. [pgPedia — энциклопедия PostgreSQL](https://pgpedia.info/) _(eng)_;
10. [postgresqlco.nf — описание и управление конфигурацией](https://postgresqlco.nf/) _(eng)_.