34.7. Использование встроенной аналитической платформы #

34.7.1. Начало #

Чтобы начать работу со встроенной аналитической платформой, выполните следующие действия:

  1. Прочитайте информацию об особенностях и ограничениях и убедитесь, что расширение pgpro_duckdb соответствует внутренним требованиям вашей организации, а также профилю нагрузки аналитических запросов.

  2. Подготовьте диаграмму оптимального развёртывания. За более подробной информацией обратитесь к разделу Рекомендации по развёртыванию.

  3. Установите расширение pgpro_duckdb.

  4. Выделите необходимые ресурсы. За более подробной информацией обратитесь к разделу Планирование ресурсов.

  5. Определите модель безопасности для работы с OLAP-ресурсами. За более подробной информацией обратитесь к разделу Настройка безопасного доступа к OLAP-ресурсам.

  6. Установите ограничения ресурсов для аналитических запросов с учётом OLTP-нагрузки. За более подробной информацией обратитесь к разделу Настройка ограничений вычислительных ресурсов.

  7. Выдайте пользователям pgpro_duckdb необходимые права доступа.

  8. Экспортируйте необходимые OLAP-данные в столбцовое представление, затем переместите их в соответствующее хранилище. За более подробной информацией обратитесь к разделу Экспорт OLAP-данных в хранилище.

  9. Создайте представления для экспортированных Parquet-файлов. За более подробной информацией обратитесь к разделу Создание представления для работы с Parquet-файлами.

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

34.7.2. Настройка безопасного доступа к OLAP-ресурсам #

Чтобы настроить безопасный доступ к OLAP-ресурсам, настройте ролевой доступ и хранилища.

34.7.2.1. Настройка ролевого доступа #

Вы можете использовать параметр конфигурации duckdb.postgres_role, чтобы указать имя роли, которая может вызывать функции pgpro_duckdb:

      postgres=# show duckdb.postgres_role;
       duckdb.postgres_role
      ----------------------

      (1 row)

По умолчанию для параметра конфигурации duckdb.postgres_role указано значение NULL, то есть вызывать функции pgpro_duckdb может только суперпользователь:

      postgres=> SELECT usename, usesuper FROM pg_user WHERE usename = current_user;
       usename | usesuper
      ---------+----------
       user1   | f
      (1 row)

      postgres=> SELECT * FROM duckdb.query('SELECT * FROM a;');
      ERROR:  DuckDB execution is not allowed because you have not been granted the duckdb.postgres_role

Чтобы разрешить членам пользовательской роли вызывать функции pgpro_duckdb, укажите имя требуемой роли, после чего перезапустите сервер:

      postgres=# ALTER SYSTEM SET duckdb.postgres_role TO 'user1';
      ALTER SYSTEM
      -- после перезапуска сервера --
      postgres=# show duckdb.postgres_role ;
       duckdb.postgres_role
      ----------------------
       user1
      (1 row)

34.7.2.2. Настройка хранилищ #

Вы можете использовать параметр конфигурации duckdb.disabled_filesystems, чтобы указать хранилища, которые будут отключены для расширения pgpro_duckdb.

Возможные значения:

  • LocalFileSystem: локальное хранилище

  • S3FileSystem: S3-хранилище

  • HTTPFileSystem: сетевое хранилище

По умолчанию локальное хранилище отключено:

      postgres=> show duckdb.disabled_filesystems;
       duckdb.disabled_filesystems
      -----------------------------
       LocalFileSystem
      (1 row)

Примечание

Перед включением локального или S3-хранилища обратитесь к разделам Особенности работы с локальным хранилищем и Рекомендации по работе с S3-хранилищем.

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

      postgres=# ALTER SYSTEM SET duckdb.disabled_filesystems TO 'LocalFileSystem,HTTPFileSystem';
      ALTER SYSTEM
      -- после перезапуска сервера --
      postgres=# show duckdb.disabled_filesystems;
        duckdb.disabled_filesystems
      --------------------------------
       LocalFileSystem,HTTPFileSystem
      (1 row)
34.7.2.2.1. Особенности работы с локальным хранилищем #

Локальное хранилище по умолчанию отключено, поэтому пользователям запрещено экспортировать или читать из него файлы:

        postgres=> show duckdb.disabled_filesystems;
         duckdb.disabled_filesystems
        -----------------------------
         LocalFileSystem
        (1 row)

        postgres=> COPY test TO 'out.parquet';
        ERROR:  (PGDuckDB/DuckdbUtilityHook_Cpp) Permission Error: File system LocalFileSystem has been disabled by configuration
        postgres=> SELECT * FROM read_parquet('test.parquet');
        ERROR:  (PGDuckDB/CreatePlan) Prepared query returned an error: 'Permission Error: File system LocalFileSystem has been disabled by configurationinput>

Если локальное хранилище включено, члены роли, указанной в параметре конфигурации duckdb.postgres_role, имеют такие же права доступа в этом хранилище, как и пользователь postgres. Это необходимо для чтения из Parquet-файлов и записи в них:

        postgres=> show duckdb.disabled_filesystems;
         duckdb.disabled_filesystems
        -----------------------------

        (1 row)

        postgres=> COPY test TO 'out.parquet';
        COPY 7
        postgres=> SELECT * FROM read_parquet('out.parquet');
         a | b
        ---+---
         1 | 2
        ...
        (7 rows)

Однако в этом случае пользователи также имеют доступ к файлам в каталоге PGDATA:

        postgres=> show duckdb.disabled_filesystems ;
         duckdb.disabled_filesystems
        -----------------------------

        (1 row)

        postgres=> SELECT pg_read_file('postgresql.auto.conf');
        ERROR:  permission denied for function pg_read_file

        postgres=> SELECT * FROM duckdb.query('SELECT content FROM read_text(''postgresql.auto.conf'')');
                              content
        -------------------------------------------------------
        # Не редактируйте этот файл вручную!                    +
        # Он будет перезаписан командой ALTER SYSTEM.+

В то время как если вы отключите локальное хранилище:

        postgres=> show duckdb.disabled_filesystems ;
         duckdb.disabled_filesystems
        -----------------------------
         LocalFileSystem
        (1 row)

        postgres=> SELECT * FROM duckdb.query('SELECT content FROM read_text(''postgresql.auto.conf'')');
        ERROR:  (PGDuckDB/CreatePlan) Prepared query returned an error: 'Permission Error: File system LocalFileSystem has been disabled by configuration

Рекомендации по использованию расширения pgpro_duckdb с локальным хранилищем:

  • Используйте локальное хранилище, только если вы уверены, что пользователи будут правильно вызывать функции pgpro_duckdb.

  • Изолируйте процессы Postgres Pro от файлов вне каталога PGDATA и файлов, которые будут прочитаны или записаны.

34.7.2.2.2. Рекомендации по работе с S3-хранилищем #

Для работы с S3-хранилищем укажите информацию о подключении. Например, если у вас развёрнут экземпляр S3-хранилища MinIO, выполните следующие действия от имени пользователя postgres:

  1. Создайте сервер для S3-хранилища:

                postgres=# CREATE SERVER my_secret1
                TYPE 's3'
                FOREIGN DATA WRAPPER duckdb
                OPTIONS (
                    endpoint '127.0.0.1:9000',
                    url_style 'path',
                    use_ssl 'FALSE'
                );
                CREATE SERVER
  2. Создайте сопоставление пользователей для пользователя, который будет работать с S3-хранилищем:

                postgres=# CREATE USER MAPPING FOR user1 SERVER my_secret1
                OPTIONS (KEY_ID 'minioadmin', SECRET 'minioadmin');
                CREATE USER MAPPING

Указанный пользователь теперь имеет права доступа, необходимые для работы с S3-хранилищем:

        postgres=> SELECT * FROM read_parquet('s3://bucket1/results.parquet');
         a | b
        ---+---
         1 | 2
         2 |
        (2 rows)

        postgres=> COPY a TO 's3://bucket1/a.parquet';
        COPY 8

Если вы создаёте сопоставление пользователей для пользовательской роли, указанной в параметре конфигурации duckdb.postgres_role, все члены этой роли смогут работать с S3-хранилищем.

Чтобы отозвать доступ к S3-хранилищу у пользователя, удалите соответствующее сопоставление пользователей:

        postgres=# DROP USER MAPPING FOR user1 SERVER my_secret1;
        DROP USER MAPPING

Чтобы отозвать доступ к S3-хранилищу у всех пользователей, отключите хранилище:

        postgres=> show duckdb.disabled_filesystems ;
          duckdb.disabled_filesystems
        ------------------------------
          LocalFileSystem,S3FileSystem
        (1 row)

        postgres=> SELECT * FROM read_parquet('s3://bucket1/results.parquet');
        ERROR:  (PGDuckDB/CreatePlan) Prepared query returned an error: 'Permission Error: File system S3FileSystem has been disabled by configuration
        postgres=> COPY a TO 's3://bucket1/a.parquet';
        ERROR:  (PGDuckDB/DuckdbUtilityHook_Cpp) Permission Error: File system S3FileSystem has been disabled by configuration

34.7.3. Экспорт OLAP-данных в хранилище #

Особенности экспорта OLAP-данных в хранилище:

  • Метод сжатия zstd с уровнем сжатия по умолчанию обеспечивает оптимальное соотношение размера файла и скорости выполнения операций.

  • Вы можете указать размер файла с помощью параметра FILE_SIZE_BYTES. Значение должно быть в диапазоне от 100 МБ до 10 ГБ.

  • Вы можете не изменять параметр ROW_GROUP_SIZE.

34.7.3.1. Экспорт OLAP-данных в столбцовое представление #

OLAP-данные экспортируются с помощью команды COPY. Вы можете экспортировать таблицу Postgres Pro целиком:

              COPY tbl TO 'output.parquet' (FORMAT parquet);
      
    

Или только необходимые OLAP-данные:

              COPY (SELECT * FROM tbl) TO 'output.parquet' (FORMAT parquet);
      
    

Вы можете использовать следующие рекомендации по структуре каталогов и экспорту в Parquet-файлы:

              COPY (SELECT * FROM tbl) TO '/rootpath/db_name/schema_name/ table_name'
        (FORMAT parquet, COMPRESSION zstd, FILE_SIZE_BYTES 1g);
      
    

34.7.3.2. Экспорт OLAP-данных в S3-хранилище #

Чтобы экспортировать OLAP-данные в S3-хранилище, укажите информацию о подключении. Например, если у вас развёрнут экземпляр S3-хранилища MinIO, выполните следующие действия от имени пользователя postgres:

  1. Создайте сервер для S3-хранилища:

                          postgres=# CREATE SERVER my_secret1
                TYPE 's3'
                FOREIGN DATA WRAPPER duckdb
                OPTIONS (
                    endpoint '127.0.0.1:9000',
                    url_style 'path',
                    use_ssl 'FALSE'
                );
                CREATE SERVER
              
            
  2. Создайте сопоставление пользователей для пользователя, который будет работать с S3-хранилищем:

                          postgres=# CREATE USER MAPPING FOR user1 SERVER my_secret1
                OPTIONS (KEY_ID 'minioadmin', SECRET 'minioadmin');
                CREATE USER MAPPING
              
            
  3. Выполните команду COPY от имени требуемого пользователя:

                          COPY (SELECT * FROM tbl) TO 's3://bucket/db_name/schema_name/table_name' (FORMAT parquet, COMPRESSION zstd, FILE_SIZE_BYTES 1g);
              
            

34.7.3.3. Поддержка секционирования #

Чтобы организовать OLAP-данные по ключам секционирования в каталоге таблиц Postgres Pro с помощью Hive-секционирования, укажите параметр PARTITION_BY при экспорте данных:

              COPY (SELECT * FROM tbl) TO 's3://bucket/db_name/schema_name/table_name' (FORMAT parquet, PARTITION_BY (year, month), COMPRESSION zstd);
      
    

Так как запись большого количества Parquet-файлов является ресурсоёмкой OLAP-операцией, выбирайте ключи секционирования таким образом, чтобы размер каждой итоговой секции составлял как минимум 100 МБ. Размер Parquet-файлов невозможно настроить вместе с параметром PARTITION_BY. Количество создаваемых в каждом каталоге (секции) Parquet-файлов соответствует количеству потоков pgpro_duckdb.

За более подробной информацией о команде COPY и формате Parquet обратитесь к официальной документации DuckDB по операторам и Parquet-файлам.

34.7.3.4. Транзакции и производительность #

Команда COPY выполняется в транзакции, потому снимок экспортированной таблицы Postgres Pro получается согласованным. Вы можете использовать явную транзакцию, чтобы экспортировать несколько согласованных таблиц, несколько раз подряд выполнив команду COPY.

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

  • При наличии доступных вычислительных ресурсов выполните команду COPY для каждой таблицы в отдельном сеансе. В этом случае в каждом сеансе необходимо подключиться к одному и тому же снимку транзакции с помощью команды SET TRANSACTION SNAPSHOT.

  • Как правило, таблицы, доступные только для добавления, имеют столбец с монотонно увеличивающимися значениями. Вы можете разделить значения на диапазоны и экспортировать их в разных транзакциях.

Обратите внимание, что вы можете указать количество процессов postgres для чтения таблиц, а также количество потоков pgpro_duckdb для экспорта OLAP-данных в Parquet-файлы. Однако конвертация из столбцового в строчное представление в настоящее время выполняется в одном потоке.

34.7.3.5. Ошибки экспорта #

Если при экспорте OLAP-данных в Parquet-файлы возникает ошибка, например из-за недостаточного дискового пространства, частично экспортированные файлы не удаляются. Для таких случаев необходимо настроить автоматическое удаление и продолжение работы.

34.7.4. Создание представления для работы с Parquet-файлами #

Расширение pgpro_duckdb использует функцию read_parquet для чтения Parquet-файлов. Эта функция возвращает специальный тип данных — duckdb.row, который обеспечивает совместимость между DuckDB и Postgres Pro. Функция read_parquet использует уникальный синтаксис для работы со столбцами:

          SELECT r['id'], r['name'] FROM read_parquet('file.parquet') r WHERE r['age'] > 21;
    
   

34.7.4.1. Создание представления для Parquet-файлов #

После экспорта OLAP-данных в Parquet-файлы вы можете работать с ними как со стандартными таблицами Postgres Pro. Для этого создайте представление для Parquet-файлов:

              CREATE VIEW parquet_table AS
        SELECT
                r['id']::BIGINT AS id,
                r['age']::SMALLINT AS age,
                r['name']::VARCHAR AS name
        FROM read_parquet('file.parquet') AS r;
      
     

В этом примере явно указаны используемые в Parquet-файлах типы данных. Это необязательно, но так вы можете назначить столбцам необходимые типы DuckDB. В противном случае будут использованы метаданные Parquet-файлов. Если типы данных не указаны явно, описание представления будет содержать уникальный тип данных duckdb.unresolved_type.

После создания представления можно выполнять стандартные аналитические запросы:

              SELECT id, name FROM parquet_table r WHERE age > 21;
      
     

34.7.4.2. Работа с Parquet-файлами с помощью шаблона поиска (glob pattern) #

Функция read_parquet может принимать списки имён Parquet-файлов. Она также позволяет использовать синтаксис шаблона поиска и указывать списки шаблонов поиска. Синтаксис шаблона поиска можно использовать для чтения каталога Parquet-файлов или нескольких каталогов, если используется Hive-секционирование.

За более подробной информацией обратитесь к официальной документации DuckDB по Parquet-файлам.

34.7.4.3. Оптимизация производительности для Parquet-файлов #

Расширение pgpro_duckdb содержит следующие оптимизации производительности для Parquet-файлов:

  • Перенос проекций на файловый уровень (projection pushdown): исключает не указанные в аналитических запросах столбцы.

  • Перенос фильтров на файловый уровень (filter pushdown): использует метаданные Parquet-файлов для чтения строк.

  • Hive-секционирование: уменьшает объём читаемых OLAP-данных. Вы можете организовать OLAP-данные по ключам секционирования в иерархии каталогов и использовать ключи секционирования в аналитических запросах. В этом случае будут прочитаны только каталоги, соответствующие указанным ключам секционирования.

За более подробной информацией обратитесь к официальной документации DuckDB по частичному чтению и переносу фильтров на файловый уровень.

34.7.5. Настройка ограничений вычислительных ресурсов #

Чтобы избежать негативного влияния на OLTP-нагрузки, важно ограничивать потребление вычислительных ресурсов аналитическими сеансами.

34.7.5.1. Ограничение потоков и потребления памяти #

Расширение pgpro_duckdb позволяет ограничивать количество потоков и потребление памяти для аналитических сеансов с помощью следующих параметров конфигурации:

Реальное потребление памяти операционной системой может быть выше. Например, настроенные ограничения не учитываются процессом выделения пространства для результатов запросов. За более подробной информацией обратитесь к официальной документации DuckDB по управлению ресурсами.

34.7.5.2. Перенос данных на диск #

Расширение pgpro_duckdb обрабатывает OLAP-данные в потоках, то есть часть за частью, по возможности избегая полной материализации. Если расширению pgpro_duckdb не хватает оперативной памяти для выполнения аналитического запроса, связанные данные помещаются во временные файлы, что существенно повышает время выполнения.

Временные файлы размещаются в каталоге PGDATA/.tmp и могут занимать до 90% дискового пространства. Каждые 24 часа выполняйте мониторинг количества временных файлов, создаваемых расширением pgpro_duckdb, и избегайте пиковых значений.

34.7.5.3. Результаты синтетических тестов одновременных нагрузок OLAP и OLTP #

Для оценки производительности был использован CH-benCHmark. Он включает в себя измерение среднего количества транзакций в секунду (TPS) за определённый период времени, а также количества параллельно выполненных аналитических запросов. В этом случае характер аналитических запросов не имеет значения, так как они выполняются в случайном порядке, и время выполнения одного аналитического запроса гораздо меньше продолжительности запуска теста.

OLTP-нагрузка была обеспечена программой pgbench, а аналитические запросы ClickBench были сгенерированы на фоне скриптом. В файле CH-benCHmark аналитические запросы TCP-H были заменены запросами ClickBench. В качестве изначальной реализации был использован citus-benchmark.

Описание теста:

  • Сервер с 64 виртуальными процессорами и 128 ГБ оперативной памяти

  • Размер данных: 14 ГБ для каждого набора данных pgbench и ClickBench, обработано в оперативной памяти

  • Продолжительность теста: 100 секунд

  • Метрики: транзакции в секунду (TPS), количество аналитических запросов и средняя нагрузка

34.7.5.3.1. Тест 1 #

Для этого теста был запущен один процесс ClickBench с 4 потоками. Количество подключений pgbench -S (select-only) отличалось для каждого запуска теста.

Таблица 34.2. Результаты теста 1

Количество подключений

TPS / аналитические запросы (средняя нагрузка)

25

287/39 (23.8)

50

487/39 (42)

100

532/38 (68)

200

610/34 (158)


34.7.5.3.2. Тест 2 #

Для этого теста были запущены 200 подключений pgbench -S (select-only). Количество процессов ClickBench с 2 потоками отличалось для каждого запуска теста.

Таблица 34.3. Результаты теста 2

Количество процессов ClickBench

TPS / аналитические запросы (средняя нагрузка)

2

574/49 (147)

4

533/66 (156)

8

522/127 (170)


34.7.5.3.3. Тест 3 #

Для этого теста были запущены 200 подключений pgbench TCP-B. Количество потоков отличалось для каждого запуска теста.

Таблица 34.4. Результаты теста 3

Количество потоков

TPS / аналитические запросы (средняя нагрузка)

0

53

1

42/17 (66)

4

42/39 (69)

Не ограничено

42/108 (86)


34.7.5.4. Одновременная нагрузка OLAP и OLTP #

Рекомендации для одновременной нагрузки OLAP и OLTP:

  • Если OLTP-сеансы используют много ядер ЦП, вы можете запустить ограниченное количество OLAP-потоков без оказания негативного влияния OLTP-нагрузку. Это обеспечивает планировщик ОС, который равномерно распределяет ресурсы ЦП между потоками.

  • Ограничьте количество потоков и потребление памяти аналитическими сеансами с помощью параметров конфигурации pgpro_duckdb.

  • Храните Parquet-файлы и каталог временных файлов в автономном физическом хранилище, чтобы избежать конкуренции между вводом и выводом.

34.7.6. Базовый сценарий работы аналитика #

В этом разделе описан базовый сценарий работы аналитика. Предполагается, что выполнены следующие предварительные требования:

  • Postgres Pro развёрнут с установленным расширением pgpro_duckdb.

  • Экземпляр S3-хранилища MinIO развёрнут и содержит Parquet-файлы.

  • Приложение DBeaver установлено и подключено к базе данных.

Базовый сценарий состоит из следующих шагов:

  1. Настройка расширения pgpro_duckdb и S3-хранилища MinIO. Администратор создаёт сервер для S3-хранилища и сопоставление пользователей для пользователя, который будет работать с S3-хранилищем. Команды выполняются от имени пользователя postgres:

              postgres=# CREATE SERVER my_secret1
              TYPE 's3'
              FOREIGN DATA WRAPPER duckdb
              OPTIONS (
                  endpoint '127.0.0.1:9000',
                  url_style 'path',
                  use_ssl 'FALSE'
              );
              CREATE SERVER
    
              postgres=# CREATE USER MAPPING FOR user1 SERVER my_secret1
              OPTIONS (KEY_ID 'minioadmin', SECRET 'minioadmin');
              CREATE USER MAPPING
  2. Создание представления для работы с Parquet-файлами:

              postgres=# CREATE VIEW orders_view AS SELECT r['o_orderkey']::bigint o_orderkey, r['o_custkey']::bigint o_custkey, r['o_orderstatus']::char o_orderstatus, r['o_totalprice']::double precision o_totalprice, r['o_orderdate']::date o_orderdate, r['o_orderpriority']::text o_orderpriority, r['o_clerk']::text o_clerk, r['o_shippriority']::bigint o_shippriority, r['o_comment']::text o_comment FROM read_parquet('s3://bucket1/orders/orders.parquet') r;
              CREATE VIEW

    В этом запросе столбцы выбираются из Parquet-файла с помощью параметра r['имя_столбца'], и типы данных указаны синтаксисом r['имя_столбца']::тип. Кроме того, для удобства работы с данными созданы псевдонимы столбцов, а также псевдоним r для параметра read_parquet.

    Теперь аналитик может работать с созданным представлением:

              test=# SELECT o_orderkey, o_totalprice FROM orders_view LIMIT 3;
               o_orderkey | o_totalprice
              ------------+--------------
                        1 |    224560.83
                        2 |     75388.65
                        3 |    255287.36
              (3 rows)
    
              test=# SELECT AVG(o_totalprice) FROM orders_view ;
                      AVG
              -------------------
               151121.1229494574
              (1 row)
  3. Работа с созданным представлением с помощью приложения DBeaver. Аналитик может подключаться к базе данных, работать с созданным представлением и выполнять аналитические запросы. Приложение DBeaver отображает типы столбцов, указанные при создании представления.