Уже оОочень давно, ещё в начале прошлой эпохи, я рассказывал про Демобазу авиаперевозок от компании Постгрес Профессиональный. С тех времён прошлом более шести лет — и недавно вышла новая версия Демобазы. И, что очень интересно, там появился генератор данных.
Подробнее рекомендую почитать следующие источники:
- [документация] Демонстрационная база данных
- [habr] Демобаза 2.0 для PostgreSQL
- [PGConf.ru] Демобаза 2.0
- [gihub] demodb
А про генератор данных подробно рассказано на соответствующей странице в гитхабе: Генератор демобазы. Можно скачать исходный код, изучить его; запустить генерацию. На странице гитхаба максимально подробно описано как установить и запустить генератор, тут вопросов быть не должно.
Поэтому в рамках данной статьи я просто покажу описанные в статье шаги (с некоторыми элементами «от себя») и вывод команд. Генерировать демобазу буду для PostgreSQL версии 18:
SELECT version();
version
---------------------------------------------------------------------------------------------------------------------------------
PostgreSQL 18.4 (Ubuntu 18.4-0ubuntu0.26.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 15.2.0-16ubuntu1) 15.2.0, 64-bit
(1 row)
Установка
1. Склонируем репозитарий:
git clone https://github.com/postgrespro/demodb
2. Перейдём в директорию куда склонировали репозитарий, подключимся к любой БД кроме demo:
psql -d pavel
3. Проверим что находимся в диретории репозитария demodb:
\! pwd /home/pavel/demodb
4. Выполним установку генератора (тут есть ERROR — это не страшно, но база demo будет пересоздана!):
\i install.sql psql:install.sql:13: ERROR: database "demo" does not exist CREATE DATABASE You are now connected to database "demo" as user "pavel". CREATE EXTENSION psql:install.sql:17: NOTICE: installing required extension "cube" CREATE EXTENSION ALTER DATABASE .. ALTER DATABASE You are now connected to database "demo" as user "pavel". SET psql:tables.sql:18: NOTICE: schema "gen" does not exist, skipping DROP SCHEMA CREATE SCHEMA CREATE TABLE COPY 10 CREATE TABLE COPY 1741 .. CREATE SEQUENCE psql:tables.sql:267: NOTICE: schema "bookings" does not exist, skipping DROP SCHEMA CREATE SCHEMA CREATE FUNCTION COMMENT ... CREATE INDEX ... COMMENT ... CREATE FUNCTION ... CREATE PROCEDURE ... CREATE FUNCTION CALL SET
4.1. И давайте сразу заглянем в лог, вдруг там будет что-нибудь интересное?
У меня Ubuntu, устанавливал PostgreSQL из пакета, поэтому адрес лога стандартный: /var/log/postgresql/
tail -16 /var/log/postgresql/postgresql-18-main.log 2026-10-05 21:47:37.788 MSK [4157248] pavel@pavel STATEMENT: /* Demonstration Database Generator Copyright (c) 2025 Postgres Professional Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
5. Проверим текущее подключение — подключены к demo:
\conninfo
Connection Information
Parameter | Value
----------------------+---------------------
Database | demo
Client User | pavel
…
(12 rows)
6. В ходе установки созданы две схемы в БД demo (public уже был):
\dn
List of schemas
Name | Owner
----------+-------------------
bookings | postgres
gen | postgres
public | pg_database_owner
(3 rows)
7. Для работы генератора требуются дополнительные расширения (btree_gist, earthdistance, cube, dblink) — они установились успешно:
\dx
List of installed extensions
Name | Version | Default version | Schema |
--------------------+---------+-----------------+------------+
btree_gist | 1.8 | 1.8 | public |
cube | 1.5 | 1.5 | public |
dblink | 1.2 | 1.2 | public |
earthdistance | 1.2 | 1.2 | public |
plpgsql | 1.0 | 1.0 | pg_catalog |
(5 rows)
8. Посмотрим таблицы в схеме bookings:
\dt bookings.*
List of tables
Schema | Name | Type | Owner
----------+-----------------+-------+-------
bookings | airplanes_data | table | pavel
bookings | airports_data | table | pavel
bookings | boarding_passes | table | pavel
bookings | bookings | table | pavel
bookings | flights | table | pavel
bookings | routes | table | pavel
bookings | seats | table | pavel
bookings | segments | table | pavel
bookings | tickets | table | pavel
(9 rows)
И в схеме gen:
\dt gen.*
List of tables
Schema | Name | Type | Owner
--------+--------------------+-------+-------
gen | airplanes_data | table | pavel
gen | airport_to_prob | table | pavel
gen | airports_data | table | pavel
gen | directions | table | pavel
gen | directions_connect | table | pavel
gen | events | table | pavel
gen | events_history | table | pavel
gen | firstnames | table | pavel
gen | lastnames | table | pavel
gen | log | table | pavel
gen | missed_flights | table | pavel
gen | passengers | table | pavel
gen | seats | table | pavel
gen | seats_remain | table | pavel
gen | stat_bookings | table | pavel
gen | stat_bookrefs | table | pavel
gen | stat_jobs | table | pavel
gen | week_traffic | table | pavel
(18 rows)
Можно подпрограммы посмотреть, они тоже создавались во время установки генератора (я немного сократил вывод):
\df generate|continue|abort|busy
List of functions
Schema | Name | Result data type | Type
--------+----------+------------------+------
public | abort | | proc
public | busy | boolean | func
public | continue | | proc
public | generate | | proc
(4 rows)
Генерация данных
1. Убедимся что наши таблицы пустые:
\dt+
List of tables
Schema | Name | Type | Owner | Persistence | Access method | Size |
----------+-----------------+-------+-------+-------------+---------------+---------+
bookings | airplanes_data | table | pavel | unlogged | heap | 16 kB |
bookings | airports_data | table | pavel | unlogged | heap | 16 kB |
bookings | boarding_passes | table | pavel | unlogged | heap | 16 kB |
bookings | bookings | table | pavel | unlogged | heap | 0 bytes |
bookings | flights | table | pavel | unlogged | heap | 16 kB |
bookings | routes | table | pavel | unlogged | heap | 16 kB |
bookings | seats | table | pavel | unlogged | heap | 16 kB |
bookings | segments | table | pavel | unlogged | heap | 16 kB |
bookings | tickets | table | pavel | unlogged | heap | 16 kB |
(9 rows)
2. Для генерации используется процедура generate:
Ей можно передавать разные параметры, запускать в несколько процессов:
CALL generate( now(), now() + interval '1 year' ); CALL generate( now(), now() + interval '1 year', 2 ); CALL continue( now() + interval '3 month', 4 );
Даты тоже можно разные передавать.
Запущу генерацию на год данных:
CALL generate( now(), now() + interval '1 year', 12 ); NOTICE: Starting job 1: ok NOTICE: Starting job 2: ok NOTICE: Starting job 3: ok NOTICE: Starting job 4: ok NOTICE: Starting job 5: ok NOTICE: Starting job 6: ok NOTICE: Starting job 7: ok NOTICE: Starting job 8: ok NOTICE: Starting job 9: ok NOTICE: Starting job 10: ok NOTICE: Starting job 11: ok NOTICE: Starting job 12: ok CALL
3. Опять заглянем в лог:
tail -16 /var/log/postgresql/postgresql-18-main.log
PL/pgSQL function process_queue(timestamp with time zone) line 22 at PERFORM
2026-10-05 22:59:38.077 MSK [4193752] postgres@demo STATEMENT: CALL process_queue('2027-10-05 19:29:29.105823+00')
2026-10-05 22:59:38.077 MSK [4191497] postgres@demo FATAL: terminating connection due to administrator command
2026-10-05 22:59:38.077 MSK [4191497] postgres@demo CONTEXT: SQL statement "SELECT pg_sleep(1)"
PL/pgSQL function process_queue(timestamp with time zone) line 22 at PERFORM
2026-10-05 22:59:38.077 MSK [4191497] postgres@demo STATEMENT: CALL process_queue('2028-01-05 19:27:44.936604+00')
2026-10-05 22:59:38.077 MSK [4193752] postgres@demo LOG: could not send data to client: Broken pipe
2026-10-05 22:59:38.077 MSK [4193752] postgres@demo CONTEXT: SQL statement "SELECT pg_sleep(1)"
PL/pgSQL function process_queue(timestamp with time zone) line 22 at PERFORM
2026-10-05 22:59:38.077 MSK [4193752] postgres@demo STATEMENT: CALL process_queue('2027-10-05 19:29:29.105823+00')
2026-10-05 22:59:38.077 MSK [4191497] postgres@demo LOG: could not send data to client: Broken pipe
2026-10-05 22:59:38.077 MSK [4191497] postgres@demo CONTEXT: SQL statement "SELECT pg_sleep(1)"
PL/pgSQL function process_queue(timestamp with time zone) line 22 at PERFORM
2026-10-05 22:59:38.077 MSK [4191497] postgres@demo STATEMENT: CALL process_queue('2028-01-05 19:27:44.936604+00')
2026-10-05 23:02:31.000 MSK [3497902] LOG: checkpoint starting: time
2026-10-05 23:02:32.887 MSK [3497902] LOG: checkpoint complete: wrote 18 buffers (0.1%), wrote 63 SLRU buffers; 0 WAL file(s) added, 0 removed, 1 recycled; write=1.810 s, sync=0.065 s, total=1.888 s; sync files=311, longest=0.006 s, average=0.001 s; distance=23655 kB, estimate=23655 kB; lsn=1/78769770, redo lsn=1/78724B60
Данных много, но не очень информативно.
4. Чтобы убедится что генератор работает — выполним команду:
SELECT busy(); busy ------ t (1 row)
5. Раз генерация работает — значит данные будут добавляться в таблицы. Снова посмотрим их размер:
\dt+
List of tables
Schema | Name | Type | Owner | Persistence | Access method | Size |
----------+-----------------+-------+-------+-------------+---------------+---------+
bookings | airplanes_data | table | pavel | unlogged | heap | 56 kB |
bookings | airports_data | table | pavel | unlogged | heap | 1288 kB |
bookings | boarding_passes | table | pavel | unlogged | heap | 16 kB |
bookings | bookings | table | pavel | unlogged | heap | 24 MB |
bookings | flights | table | pavel | unlogged | heap | 752 kB |
bookings | routes | table | pavel | unlogged | heap | 128 kB |
bookings | seats | table | pavel | unlogged | heap | 128 kB |
bookings | segments | table | pavel | unlogged | heap | 86 MB |
bookings | tickets | table | pavel | unlogged | heap | 81 MB |
(9 rows)
6. Посмотрим во внутренний лог генератора (расшифровка полей есть на странице гитхаба):
SELECT * FROM gen.log ORDER BY at DESC LIMIT 15;
at | pid | severity | message
-------------------------------+-------+----------+----------------------------------------------------------------
2026-10-05 20:06:16.042326+00 | 24254 | 0 | SCL -> CJC: 351 x 4, traffic = 1123 pass/week
2026-10-05 20:06:16.04006+00 | 24254 | 0 | CJC -> SCL: 351 x 4, traffic = 1123 pass/week
2026-10-05 20:06:16.037564+00 | 24254 | 0 | FRA -> CJC: 789 x 1, traffic = 5 pass/week
2026-10-05 20:06:16.032979+00 | 24254 | 0 | CJC -> FRA: 789 x 1, traffic = 5 pass/week
2026-10-05 20:06:15.829715+00 | 24260 | 0 | New boarding passes: 31610
2026-10-05 20:06:15.827177+00 | 24260 | 0 | Book-ref retries = 4 (0.000 retries/booking)
2026-10-05 20:06:15.827056+00 | 24260 | 0 | New bookings: 14150 (forceoneway 3972), nopath 2149, noseat 84
2026-10-05 20:06:15.724905+00 | 24254 | 0 | Building routes, range ["2027-01-05 20:00:16.82558+00","2027-02-05 20:00:16.82558+00")
2026-10-05 20:06:15.724731+00 | 24260 | 0 | 2026-11-05: one day in 00:00:17.883295
2026-10-05 20:05:57.891881+00 | 24260 | 0 | Book-ref retries = 1 (0.000 retries/booking)
2026-10-05 20:05:57.891793+00 | 24260 | 0 | New bookings: 13947 (forceoneway 3858), nopath 2386, noseat 83
2026-10-05 20:05:57.841503+00 | 24260 | 0 | 2026-11-04: one day in 00:00:11.483255
2026-10-05 20:05:57.841336+00 | 24250 | 0 | Vacuum
2026-10-05 20:05:46.413316+00 | 24259 | 0 | Book-ref retries = 2 (0.000 retries/booking)
2026-10-05 20:05:46.412604+00 | 24259 | 0 | New bookings: 13935 (forceoneway 3991), nopath 2107, noseat 49
(15 rows)
Можно запустить отображение записей из лога с обновлением раз в несколько секунд — залипательное зрелище!
7. Прекратить генерацию можно с помощью команды:
CALL abort(); CALL SELECT busy(); busy ------ f (1 row)
8. Уже сгенерированные данные остались в таблицах:
\dt+
List of tables
Schema | Name | Type | Owner | Persistence | Access method | Size |
----------+-----------------+-------+-------+-------------+---------------+---------+
bookings | airplanes_data | table | pavel | unlogged | heap | 56 kB |
bookings | airports_data | table | pavel | unlogged | heap | 1288 kB |
bookings | boarding_passes | table | pavel | unlogged | heap | 18 MB |
bookings | bookings | table | pavel | unlogged | heap | 30 MB |
bookings | flights | table | pavel | unlogged | heap | 944 kB |
bookings | routes | table | pavel | unlogged | heap | 168 kB |
bookings | seats | table | pavel | unlogged | heap | 128 kB |
bookings | segments | table | pavel | unlogged | heap | 106 MB |
bookings | tickets | table | pavel | unlogged | heap | 102 MB |
(9 rows)
9. Продолжить генерацию можно с того же места, на котором остановились:
CALL continue( now() + interval '3 month', 12 ); NOTICE: Starting job 1: ok ... NOTICE: Starting job 12: ok CALL
10. Для проверки демобазы нужно вызвать команду check (выдаёт много данных):
\i check.sql
=== Generation errors in log
errors
--------
0
(1 row)
=== Generation stats
num_bookings | book_date_from | book_date_to
--------------+-------------------------------+-------------------------------
530884 | 2026-10-05 20:00:24.926673+00 | 2026-11-11 04:49:43.079322+00
(1 row)
…
=== Flight statuses
status | count
-----------+-------
Boarding | 2
Delayed | 8
Departed | 19
Cancelled | 51
On Time | 163
Arrived | 934
Scheduled | 10629
(7 rows)
…
11. Проверим результат проверки демобазы 🙂
SELECT status, count(status) FROM flights GROUP BY status ORDER BY 2; status | count -----------+------- Boarding | 2 Delayed | 8 Departed | 19 Cancelled | 51 On Time | 163 Arrived | 934 Scheduled | 10629 (7 rows)
12. За процессом генерации можно и из ОС следить:
Это я максимум параллельных процессов запустил 🙂
13. Размер после окончания генерации данных за год (генерация годовой демобазы заняла чуть больше двух часов):
\dt+
List of tables
Schema | Name | Type | Owner | Persistence | Access method | Size |
----------+-----------------+-------+-------+-------------+---------------+---------+
bookings | airplanes_data | table | pavel | unlogged | heap | 56 kB |
bookings | airports_data | table | pavel | unlogged | heap | 1288 kB |
bookings | boarding_passes | table | pavel | unlogged | heap | 891 MB |
bookings | bookings | table | pavel | unlogged | heap | 267 MB |
bookings | flights | table | pavel | unlogged | heap | 6048 kB |
bookings | routes | table | pavel | unlogged | heap | 560 kB |
bookings | seats | table | pavel | unlogged | heap | 128 kB |
bookings | segments | table | pavel | unlogged | heap | 932 MB |
bookings | tickets | table | pavel | unlogged | heap | 880 MB |
(9 rows)
\i check.sql
=== Generation errors in log
errors
--------
0
(1 row)
=== Generation stats
num_bookings | book_date_from | book_date_to
--------------+-------------------------------+-------------------------------
4909535 | 2026-10-06 17:45:06.577123+00 | 2027-10-06 17:44:36.764306+00
(1 row)
...
=== Flight statuses
status | count
-----------+-------
Boarding | 0
Delayed | 11
Departed | 14
On Time | 174
Cancelled | 367
Scheduled | 10579
Arrived | 59572
(7 rows)
...
=== Cancelled flights fraction
actual_cancelled_frac | target_cancelled_frac
------------------------+-----------------------
0.00518969978930101673 | 0.005
(1 row)
...
Классный генератор с огромным потенциалом! На том же хабре было уже несколько статей которые генерировали нагрузку на базу с помощью Генератора демобазы. Есть куча параметров, которые можно поменять и смотреть что изменится. Эти параметры описаны на той же странице репозитария, в разделе Настройка.
Ну и я тоже поэкспериментирую, но чуть попозже.

Leave a Reply