Генератор демобазы от PostgresPro

PostgreSQLУже оОочень давно, ещё в начале прошлой эпохи, я рассказывал про Демобазу авиаперевозок от компании Постгрес Профессиональный. С тех времён прошлом более шести лет — и недавно вышла новая версия Демобазы. И, что очень интересно, там появился генератор данных.

Подробнее рекомендую почитать следующие источники:

А про генератор данных подробно рассказано на соответствующей странице в гитхабе: Генератор демобазы. Можно скачать исходный код, изучить его; запустить генерацию. На странице гитхаба максимально подробно описано как установить и запустить генератор, тут вопросов быть не должно.

Поэтому в рамках данной статьи я просто покажу описанные в статье шаги (с некоторыми элементами «от себя») и вывод команд. Генерировать демобазу буду для 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)
...

 

Классный генератор с огромным потенциалом! На том же хабре было уже несколько статей которые генерировали нагрузку на базу с помощью Генератора демобазы. Есть куча параметров, которые можно поменять и смотреть что изменится. Эти параметры описаны на той же странице репозитария, в разделе Настройка.

Ну и я тоже поэкспериментирую, но чуть попозже.


Be the first to comment

Leave a Reply

Ваш Mail не будет опубликован.


*