Русский
Русский
English
Статистика
Реклама

Postgres

История нашего open source как мы сделали сервис аналитики на Go и выложили его в открытый доступ

15.10.2020 14:05:55 | Автор: admin
В настоящее время практически каждая компания в мире собирает статистику о действиях пользователя на web ресурсе. Мотивация понятна компании хотят знать как используется их продукт/веб сайт и лучше понимать своих пользователей. Конечно на рынке существует большое количество инструментов для решения данной проблемы от систем аналитики, которые предоставляют данные в виде дашбордов и графиков (например Google Analytics) до Customer Data Platform, которые позволяют собирать и агрегировать данные из разных источников в любом хранилище (например Segment).

Но мы нашли проблему, которая еще не была решена. Так родился EventNative open-source сервис аналитики. O том, почему мы пошли на разработку собственного сервиса, что нам это дало и что в итоге получилось (с кусками кода), читайте под катом




Зачем нам разрабатывать собственный сервис?


Это были девяностые, мы выживали как могли. 2019 год, мы разрабатывали API First Customer Data Platform kSense, которая позволяла агрегировать данные из разных источников (Facebook ads, Stripe, Salesforce, Google play, Google Analytics и др) для более удобного анализа данных, выявления зависимостей и т.д. Мы заметили, что многие пользователи используют нашу платформу для анализа данных именно Google Analytics (далее GA). С некоторыми пользователями мы поговорили и выяснили, что им нужны данные аналитики их продукта, которые они получают с помощью GA, но Google сэмплирует данные и для многих GA User interface не является эталоном удобства. Мы провели достаточное количество бесед с нашими пользователями и поняли, что многие также использовали платформу Segment (которая, кстати, буквально на днях была продана за 3.2 млрд$). Они устанавливали Segment javascript пиксель на свой web ресурс и данные о поведении их пользователей загружались в указанную базу данных (например Postgres). Но и у Segment есть свой минус цена. К примеру, если у веб ресурса 90,000 MTU (monthly tracked users) то необходимо оплатить в кассу ~1,000 $ в месяц. Также была и третья проблема некоторые расширения для браузера (такие как AdBlock) блокировали сбор аналитики т.к. http запросы из браузера отправлялись на домены GA и Segment. Исходя из желания наших клиентов, мы сделали сервис аналитики, который собирает полный набор данных (без сэмплинга), бесплатный и может работать на собственной инфраструктуре.

Как устроен сервис


Сервис состоит из трех частей: javascript пиксель (который мы впоследствии переписали на typescript), серверная часть реализована на языке GO и в качестве in-house базы данных планировалось использовать Redshift и BigQuery (позже добавили поддержку Postgres, ClickHouse и Snowflake).

Структуру событий GA и Segment решили оставить без изменения. Все, что было нужно, это дублировать все события с web ресурса, где установлен пиксель, в наш бекенд. Как оказалось, это сделать несложно. Javascript пиксель переопределял оригинальный метод библиотеки GA на новый, который дублировал событие в нашу систему.

//'ga' - стандартное название переменной Google Analyticsif (window.ga) {    ga(tracker => {        var originalSendHitTask = tracker.get('sendHitTask');        tracker.set('sendHitTask', (model) => {            var payLoad = model.get('hitPayload');            //отправка оригинального события в GA            originalSendHitTask(model);            let jsonPayload = this.parseQuery(payLoad);            //отправка события в наш сервис            this.send3p('ga', jsonPayload);        });    });}

С пикселем Segment все проще, он имеет middleware методы, одним из них мы и воспользовались.

//'analytics' - стандартное название переменной Segmentif (window.analytics) {    if (window.analytics.addSourceMiddleware) {        window.analytics.addSourceMiddleware(chain => {            try {//дублирование события в наш сервис                this.send3p('ajs', chain.payload);            } catch (e) {                LOG.warn('Failed to send an event', e)            }    //отправка оригинального события в Segment            chain.next(chain.payload);        });    } else {        LOG.warn("Invalid interceptor state. Analytics js initialized, but not completely");    }} else {    LOG.warn('Analytics.js listener is not set.');}

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

//Отправка событий с произвольным json объектомeventN.track('product_page_view', {    product_id: '1e48fb70-ef12-4ea9-ab10-fd0b910c49ce',    product_price: 399.99,    price_currency: 'USD'    product_release_start: '2020-09-25T12:38:27.763000Z'});

Далее поговорим про серверную часть. Backend должен принимать http запросы, наполнять их дополнительной информацией, к примеру, гео данными (спасибо maxmind за это) и записывать в базу данных. Мы хотели сделать сервис максимально удобным, чтобы его можно было использовать с минимальной конфигурацией. Мы реализовали функционал определения схемы данных на основе структуры входящего json события. Типы данных определяются по значениям. Вложенные объекты раскладываются и приводятся к плоской структуре:

//входящий json{  "field_1":  {    "sub_field_1": "text1",    "sub_field_2": 100  },  "field_2": "text2",  "field_3": {    "sub_field_1": {      "sub_sub_field_1": "2020-09-25T12:38:27.763000Z"    }  }}//результат{  "field_1_sub_field_1":  "text1",  "field_1_sub_field_2":  100,  "field_2": "text2",  "field_3_sub_field_1_sub_sub_field_1": "2020-09-25T12:38:27.763000Z"}

Однако массивы на данный момент просто конвертируются в строку т.к. не все реляционные базы данных поддерживают повторяющиеся поля (repeated fields). Также есть возможность изменять названия полей или удалять их с помощью опциональных правил маппинга. Они позволяют менять схему данных, если это потребуется или приводить один тип данных к другому. К примеру, если в json поле находится строка с timestamp (field_3_sub_field_1_sub_sub_field_1 из примера выше) то для того чтобы создать поле в базе данных с типом timestamp, необходимо написать правило маппинга в конфигурации. Другими словами, тип данных поля определяется сначала по json значению, а затем применяется правило приведения типов (если оно сконфигурировано). Мы выделили 4 основных типа данных: STRING, FLOAT64, INT64 и TIMESTAMP. Правила маппинга и приведения типов выглядят следующим образом:

rules:  - "/field_1/subfield_1 -> " #правило удаления поля  - "/field_2/subfield_1 -> /field_10/subfield_1" #правило переноса поля  - "/field_3/subfield_1/subsubfield_1 -> (timestamp) /field_20" #правило переноса поля и приведения типа

Алгоритм определения типа данных:

  • преобразование json структуры в плоскую структуру
  • определение типа данных полей по значениям
  • применение правил маппинга и приведения типов

Тогда из входящей json структуры:

{    "product_id":  "1e48fb70-ef12-4ea9-ab10-fd0b910c49ce",    "product_price": 399.99,    "price_currency": "USD",    "product_type": "supplies",    "product_release_start": "2020-09-25T12:38:27.763000Z",    "images": {      "main": "picture1",      "sub":  "picture2"    }}

будет получена схема данных:

"product_id" character varying,"product_price" numeric (38,18),"price_currency" character varying,"product_type" character varying,"product_release_start" timestamp,"images_main" character varying,"images_sub" character varying

Также мы подумали, что пользователь должен иметь возможность настроить партиционирование или разделять данные в БД по другим критериям и реализовали возможность задавать имя таблицы константой или выражением в конфигурации. В примере ниже событие будет сохранено в таблицу с именем, вычисленным на основе значений полей product_type и _timestamp (например supplies_2020_10):

tableName: '{{.product_type}}_{{._timestamp.Format "2006_01"}}'

Однако структура входящих событий может изменяться в runtime. Мы реализовали алгоритм проверки разницы между структурой существующей таблицы и структурой входящего события. Если разница найдена таблица будет обновлена новыми полями. Для этого используется patch SQL запрос:

#Пример для PostgresALTER TABLE "schema"."table" ADD COLUMN new_column character varying

Архитектура




Зачем нужно записывать события на файловую систему, а не просто писать их сразу в БД? Базы данных не всегда демонстрируют высокую производительность при большом количестве вставок (рекомендации Postgres). Для этого Logger записывает входящие события в файл и уже в отдельной горутине (потоке) File reader читает файл, далее происходит преобразование и определение схемы данных. После того как Table manager убедится, что схема таблицы актуальна данные будут записаны в БД одним батчем. Впоследствии мы добавили возможность записывать данные напрямую в БД, но применяем такой режим для событий, которых не много например конверсии.

Open Source и планы на будущее


В какой-то момент сервис стал похож на полноценный продукт и мы решили выложить его в Open Source. На текущий момент реализованы интеграции с Postgres, ClickHouse, BigQuery, Redshift, S3, Snowflake. Все интеграции поддерживают как batch, так и streaming режимы загрузки данных. Добавлена поддержка запросов через API.
Текущая интеграционная схема выглядит следующим образом:



Несмотря на то что сервис можно использовать самостоятельно (например с помощью Docker), у нас также есть hosted версия, в которой можно настроить интеграцию с хранилищем данных, добавить CNAME на свой домен и посмотреть статистику по количеству событий. Наши ближайшие планы добавление возможности агрегировать не только статистику с веб ресурса, но и данные из внешних источников данных и сохранять их в любое хранилище на выбор!

GitHub
Документация
Slack

Будем рады если EventNative поможет решить ваши задачи!
Подробнее..

PGHero дашборд для мониторинга БД PostgeSQL

23.03.2021 12:19:49 | Автор: admin

Всем привет. Сегодня я бы хотел поделиться рецептом установки утилиты PGHero с подключением нескольких баз данных. PGHero это простенькая утилита, написанная на Ruby, с минималистичным дашбордом для мониторинга производительности БД PostgreSQL.

Что может показать нам PGHero:

  • статистику по запросам: количество вызовов, среднее и суммарное время выполнения (с возможностью хранения истории);

  • активные в данный момент запросы;

  • информацию о таблицах: занимаемое на диске место, даты последних запусков VACUUM и ANALYSE;

  • информацию об индексах: занимаемое на диске место, наличие дублируемых/неиспользуемых индексов. Также может порекомендовать добавить индекс при наличии сложных запросов с Seq Scan;

  • статистику по открытым подключениям к БД;

  • вывод основных настроек БД, влияющих на производительность (shared_buffers, work_mem, maintenance_work_mem и т.д.)


Одна из очень удобных возможностей утилиты просмотр динамики среднего времени выполнения запросов (на основе статистики стандартного расширения PostgreSQL pg_stat_statements).

Выглядит это в интерфейсе PGHero вот так:


Настройка баз данных

Следующие шаги нужно проделать для каждой БД, которую мы собираемся подключать к PGHero.

Запросы нужно выполнять под суперпользователем.

  1. Устанавливаем расширение pg_stat_statements (если еще не установлено):

Откройте файл postgresql.conf в текстовом редакторе и измените строку shared_preload_libraries:

shared_preload_libraries = 'pg_stat_statements'pg_stat_statements.track_utility = false

Перезапускаем сервер PostgreSQL:

sudo service postgresql restart

Создаем расширение и сбрасываем статистику:

create extension pg_stat_statements;select pg_stat_statements_reset();
  1. Создаем в БД отдельного пользователя для PGHero (чтобы не давать утилите полные права над базой).

В следующем запросе заменяем эти значения в угловых скобках на свои:

<pghero_password> пароль для пользователя pghero;

<db_name> имя вашей БД;

<migrations_user> имя основной роли с доступом к текущей БД.

CREATE SCHEMA pghero;-- view queriesCREATE OR REPLACE FUNCTION pghero.pg_stat_activity() RETURNS SETOF pg_stat_activity AS$$  SELECT * FROM pg_catalog.pg_stat_activity;$$ LANGUAGE sql VOLATILE SECURITY DEFINER;CREATE VIEW pghero.pg_stat_activity AS SELECT * FROM pghero.pg_stat_activity();-- kill queriesCREATE OR REPLACE FUNCTION pghero.pg_terminate_backend(pid int) RETURNS boolean AS$$  SELECT * FROM pg_catalog.pg_terminate_backend(pid);$$ LANGUAGE sql VOLATILE SECURITY DEFINER;-- query statsCREATE OR REPLACE FUNCTION pghero.pg_stat_statements() RETURNS SETOF pg_stat_statements AS$$  SELECT * FROM public.pg_stat_statements;$$ LANGUAGE sql VOLATILE SECURITY DEFINER;CREATE VIEW pghero.pg_stat_statements AS SELECT * FROM pghero.pg_stat_statements();-- query stats resetCREATE OR REPLACE FUNCTION pghero.pg_stat_statements_reset() RETURNS void AS$$  SELECT public.pg_stat_statements_reset();$$ LANGUAGE sql VOLATILE SECURITY DEFINER;-- improved query stats reset for Postgres 12+ - delete for earlier versionsCREATE OR REPLACE FUNCTION pghero.pg_stat_statements_reset(userid oid, dbid oid, queryid bigint) RETURNS void AS$$  SELECT public.pg_stat_statements_reset(userid, dbid, queryid);$$ LANGUAGE sql VOLATILE SECURITY DEFINER;-- suggested indexesCREATE OR REPLACE FUNCTION pghero.pg_stats() RETURNSTABLE(schemaname name, tablename name, attname name, null_frac real, avg_width integer, n_distinct real) AS$$  SELECT schemaname, tablename, attname, null_frac, avg_width, n_distinct FROM pg_catalog.pg_stats;$$ LANGUAGE sql VOLATILE SECURITY DEFINER;CREATE VIEW pghero.pg_stats AS SELECT * FROM pghero.pg_stats();-- create userCREATE ROLE pghero WITH LOGIN ENCRYPTED PASSWORD '<pghero_password>';GRANT CONNECT ON DATABASE <db_name> TO pghero;ALTER ROLE pghero SET search_path = pghero, pg_catalog, public;GRANT USAGE ON SCHEMA pghero TO pghero;GRANT SELECT ON ALL TABLES IN SCHEMA pghero TO pghero;-- grant permissions for current sequencesGRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO pghero;-- grant permissions for future sequencesALTER DEFAULT PRIVILEGES FOR ROLE <migrations_user> IN SCHEMA public GRANT SELECT ON SEQUENCES TO pghero;

Установка и запуск PGHero

Допустим, у нас есть три таблицы: db_one, db_two и db_three. Мы хотим по всем трем отображать статистику в PGHero (вместе с историей запросов и размеров таблиц). Важный момент: для хранения истории запросов и размеров таблиц нужно завести в одной из баз данных отдельные таблицы, где будет храниться эта статистика.

CREATE TABLE "pghero_query_stats" (  "id" bigserial primary key,  "database" text,  "user" text,  "query" text,  "query_hash" bigint,  "total_time" float,  "calls" bigint,  "captured_at" timestamp);CREATE INDEX ON "pghero_query_stats" ("database", "captured_at");CREATE TABLE "pghero_space_stats" (  "id" bigserial primary key,  "database" text,  "schema" text,  "relation" text,  "size" bigint,  "captured_at" timestamp);CREATE INDEX ON "pghero_space_stats" ("database", "captured_at");

Мы будем хранить эти таблицы в БД db_one (хотя можно завести отдельную базу для этой статистики). Далее создаем на сервере файл конфигурации pghero.yml со следующим содержимым (подставляем актуальные настройки):

# Конфигурационные урлы для наших БДdatabases:  db_one:    url: postgres://pghero:secret_pass@mydomain.ru:53001/db_one  db_two:    url: postgres://pghero:secret_pass@mydomain.ru:53001/db_two    capture_query_stats: db_one  db_three:    url: postgres://pghero:secret_pass@mydomain.ru:53001/db_three    capture_query_stats: db_one# Минимальная длительность запросов (в секундах), которые будут считаться долгимиlong_running_query_sec: 60# Минимальная длительность запросов (в миллисекундах), которые будут считаться медленнымиslow_query_ms: 250# Минимальное кол-во вызовов запросов, которые будут считаться медленнымиslow_query_calls: 100# Минимальное количество соединений для показа предупрежденияtotal_connections_threshold: 100# Таймаут для explain-запросовexplain_timeout_sec: 10# Нормализация запросов (замена значений запроса нумерованными параметрами)filter_data: true# Basic авторизацияusername: pgheropassword: secret_pass# Таймзонаtime_zone: "Europe/Moscow"

Переходим к установке. Документация предлагает нам несколько способов:

  1. Docker-контейнер;

  2. отдельная служба на Linux;

  3. gem-пакет Ruby;

Мы будем использовать первый способ запуск в виде Docker-контейнера. Для этого в папке с файлом конфигурации pghero.yml нужно добавить Docker-файл с таким содержимым:

docker build -t mypghero .docker run -ti -p 12345:8080 mypghero

Теперь собираем образ на основе Docker-файла и запускаем контейнер на нужном порту:

docker build -t mypghero .docker run -ti -p 12345:8080 mypghero

Теперь дашборд должен быть доступен по адресу http://123.45.67.89/12345. Не забывайте про basic-авторизацию, логин и пароль мы указывали в pghero.yml.


Запуск cron-jobs для сохранения истории

Последний этап: нужно настроить автозапуск по крону скриптов для сохранения в БД истории по запросам (capture_query_stats) и размерам таблиц (capture_space_stats).

Документация рекомендует запускать capture_query_stats раз в 5 минут, а capture_space_stats раз в сутки (но тут нужно решать по ситуации). Запускаем в командной строке crontab -e и добавляем строки для запуска скриптов:

*/5 * * * *     /usr/bin/docker run --rm my-pghero bin/rake pghero:capture_query_stats15 2 * * *     /usr/bin/docker run --rm my-pghero bin/rake pghero:capture_space_stats

Вот и всё. Спасибо за внимание.

Демо-версию утилиты можно посмотреть здесь. Исходный код и документация.

Подробнее..

PostGis. Как найти ошибку в пространственном запросе?

04.09.2020 08:20:07 | Автор: admin
image

Добрый день! Я Виктор, разработчик в Gems development.
Ежедневно наша команда работает с пространственными данными разной сложности и качества. При выполнении операции пространственного пересечения с помощью Postgis в СУБД Postgresql мы столкнулись со следующей ошибкой:
XX000: GEOSIntersects: TopologyException: side location conflict at 10398.659 3844.9200000000001

Запрос, приводящий к ошибке, выглядит так:
select q1.key,st_asGeoJson(geoloc)    from usahalinsk.V_GEO_OOPT q1         where ST_Intersects(geoloc,                ST_GeomFromGeoJSON('{"type":"Polygon","coordinates":                    [[[11165.15,2087.5],[11112,2066.6],[11127.6,2022.5],                    [11122.6,2020.7],                    [11122.25,2021.2],[11107.07,2015.7],                    [11121,1947],[11123.48,1922.99],[11128.42,1874.4],                    [11131.5,1875],[11140.96,1876.81],[11160.73,1880.59],                    [11201.04,1888.3],[11194.2,1908],[11221.93,1916.57],                    [11223.3,1917],[11165.15,2087.5]]]}'))

Решение этой проблемы блокирует работу пользователей, так как не позволяет строить отчёты по данным и замедляет работу по оказанию услуг. Многие действия в разрабатываемой нами системе, такие как: подготовка схемы расположения земельного участка, подготовка градостроительного плана земельного участка и другие, используют пространственные операции подобные этой.

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



Мы провели собственное расследование по поиску причин ошибки и хотим рассказать об этом.
В настоящий момент мы используем Postgis 2.4 и Postgresql 9.6. Перейдем сразу к практике. Проверим константную геометрию на валидность и находим, что все работает корректно.


Можно предположить, что дело в таблице (представлении) usahalinsk.V_GEO_OOPT в котором мы ищем пересечения. Для того, чтобы подтвердить гипотезу, проверим эти данные тоже.



Но и здесь ошибок не находим. Кроме того, данные в выборку не попали вообще. Если бы они были, то задача решалась бы исправлением найденных записей через функцию Postgis st_makeValid.
Но ошибок в представлении нет, а запрос не выполняется. Предлагаем посмотреть его план.


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

Наше представление usahalinsk.V_GEO_OOPT построено как выборка из таблицы с пространственными данными usahalinsk.d_geometry и по полю с геометрией создан пространственный индекс.
Значит, при выполнении запроса идет чтение индекса и где-то в таблице, не попадая в нашу выборку, есть невалидные пространственные данные, которые попали в индекс, т.к. он построен по всей таблице.
Давайте попробуем удалить индекс:
DROP INDEX usahalinsk.d_geometry_cs1_all_sx;

И попробуем выполнить проблемный запрос.



Он выполнился без ошибок. Подтверждаем, что дело в индексе.
Можно вернуть индекс, но с условием на корректную геометрию:
CREATE INDEX d_geometry_cs1_all_sx  ON usahalinsk.d_geometry  USING gist(geoloc)  where st_isvalid(geoloc)=true;

Проверим выполнение и посмотрим план.



Запрос выполнился без ошибок, индекс в плане также используется.
Из минусов такого решения может быть замедление вставки/обновления, т.к. дополнительно будет проверяться условие при перестроении индекса.
Вернем это изменение назад и попробуем всё-таки найти из-за каких объектов в индексе наш запрос не может выполниться.
DROP INDEX usahalinsk.d_geometry_cs1_all_sx; CREATE INDEX d_geometry_cs1_all_sx  ON usahalinsk.d_geometry  USING gist  (geoloc);


Напомню, что у нас есть координаты места ошибки:
XX000: GEOSIntersects: TopologyException: side location conflict at 10398.659 3844.9200000000001


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

select key,ST_IsValidReason(geoloc)from usahalinsk.d_geometry     where st_isvalid(geoloc)!=true        and ST_AsText(geoloc) like '%3844.9200000000001%';        select key,ST_IsValidReason(geoloc)from usahalinsk.d_geometry     where st_isvalid(geoloc)!=true        and ST_IsValidReason(geoloc) like '%3844.9200000000001%';


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

do$$declare    tKey bigint;    rec record;    error_text text;    --Тест ошибки    error_info text:='GEOSIntersects: TopologyException: side location conflict at 10398.659 3844.9200000000001';begin    --Перебираем все данные в таблице    for rec in(select key from usahalinsk.d_geometry)    loop        begin            select key into tKey            from (select * from usahalinsk.d_geometry q1                                 --сравнение по первичному ключу                        where q1.key=rec.key                            and ST_Intersects(geoloc,                                    --константная геометрия                                    ST_GeomFromGeoJSON('{"type":"Polygon","coordinates":[[[11165.15,2087.5],                                    [11112,2066.6],[11127.6,2022.5],[11122.6,2020.7],                                    [11122.25,2021.2],[11107.07,2015.7],[11121,1947],                                                    [11123.48,1922.99],[11128.42,1874.4],[11131.5,1875],[11140.96,1876.81],                                    [11160.73,1880.59],[11201.04,1888.3],[11194.2,1908],[11221.93,1916.57],[11223.3,1917],                                    [11165.15,2087.5]]]}'))) geoQ;                exception when others then                --получаем ошибку если она есть              GET STACKED DIAGNOSTICS error_text = MESSAGE_TEXT;            --Если её тест равен искомому, то выводим ключ              if error_text=error_info then                raise info '%',rec.key;                end if;                          end;    end loop;end$$;

В результате получаем три ключа геометрии, которые легко исправить:
update usahalinsk.d_geometry set cs1_geometry_polygone=st_collectionextract(st_makevalid(geoloc),3)where key in(1000010001988961,1000010001989399,1000010004293508);


Отвечу на возникающий вопрос: почему нельзя исправить всю ошибочную геометрию в таблице, чтобы не искать выборочно причины?.
Дело в том, что пространственные данные поступают к нам в систему из различных источников (в т.ч. из Росреестра) и мы не можем выполнять исправление (как правило, оно сопровождается искажением) всех данных. Получив нужные ключи, мы анализируем какие данные они представляют и можно ли их исправить.

Тривиальная задача поиска причины ошибки может превратиться в целое расследование со скриптом исправления в конце.

Более сложный вариант задачи: как быть, если выполняется пересечение не с константой, а с другой таблицей? Как вариант, выполнять пересечение каждого из участвующих объектов первой таблицы с каждым объектом второй. И отлавливать исключения.

А как часто вы сталкиваетесь с проблемами геометрии и как обеспечиваете качество пространственных данных?
Подробнее..

Postgresso 24

07.09.2020 16:04:06 | Автор: admin

Жизнь продолжается. А мы продолжаем знакомить вас с самыми интересными новостями PostgreSQL.
На этот раз мы решили немного изменить формат Постгрессо: теперь никакого информационного равноправия. Об одних релизах и статьях будем рассказывать подробней, о других в паре строк. Выбор субъективен, конструктивная критика приветствуется.


Релизы


PostgreSQL 13 beta 3

В 3-й бете есть изменения по сравнению с 2-й бетой, смотрите на страничке релиза.

Одновременно с Beta 3 вышли обновления: 12.4, 11.9, 10.14, 9.6.19 и 9.5.23. В них закрыты две обнаруженные бреши в безопасности, связанные с путём поиска (search_path) элементов (таблиц, функций, операторов и так далее) при создании расширений и при логической репликации. Два с лишним года назад была найдена уязвимость CVE-2018-1058, позволяющая использовать особенности работы с переменной search_path (она определяет порядок поиска в схемах при обращении к объектам БД) для запуска злокозненного кода. При неаккуратном использовании этой переменной, враг может перехватить управление над выполнением запросов и затем запустить произвольный SQL-код с правами атакуемого пользователя. Об этом можно прочитать, например, здесь. Эти опасности были объяснены, меры предосторожности перечислены. Теперь оказалось, что мер недостаточно при логической репликации и при создании расширений.

Теперь при логической репликации процессы send и receive будут исполняться с пустой строкой search_path. При создании расширений атакующий, если у него были права создавать новые объекты в расширении, мог запускать опасный код под суперпользователем. Сейчас расширения подправили и создали инструкцию для тех, кто собирается разрабатывать новые расширения.

За beta3 не последует beta4: релизная группа, то есть Джонатан Кац (Johnathan S. Katz), Альваро Эррера (Alvaro Herrera) и Питер Гайген (Peter Peter Geoghegan) пишут 2 сентября, что, проанализировав незакрытые пункты, можно сразу готовить релиз-кандидат 1 (RC1) на 17-е сентября. И, если критических проблем не обнаружится, 24-го сентября уже основную версию PostgreSQL 13. Ну а о том, много ли нового в Чёртовой Дюжине, мы уже писали.

Новые релизы Postgres Pro Enterprise/Standard

Вышли версии Postgres Pro Enterprise 12.4.1, 11.9.1, 10.14.1, 9.6.19.1, Standard 12.4.1, 11.9.1, 10.14.1, 9.6.19.1.

Изменения в Enterprise 12.4.1, например, такие:
  • устранена ошибка в оптимизации планировщика, приводившая к неправильной оценке количества строк при включённом параметре enable_compound_index_stats;
  • исправлена ошибка в расширении pgpro_scheduler, приводившая к тому, что функция schedule.stop() могла не остановить выполняющиеся задания;
  • улучшено расширение rum: при выполнении запросов с весами теперь не требуется перепроверять результаты этих запросов по таблице, так что они выполняются гораздо быстрее;
  • исправлены ошибки и в BRIN;
  • устранена ошибка, вследствие которой могли теряться результаты при обработке поисковых запросов с использованием оператора отрицания;
  • в новой версии multimaster включена функциональность, реализованная в Postgres Pro Enterprise версии 11.8.1 (ранее она оставалась недоступной при обновлении Postgres Pro Enterprise);
  • приложение pg_probackup обновлено до версии 2.4.2.

Last but not least (а для многих и самое важное):
12.4.1 и 11.9.1 теперь умеют благодаря опыту Антона Дорошкевича (ИнфоСофт) и усилиям Андрея Билле (Postgres Professional) при установке настраивать инстанс на работу с 1С (pg-setup inidb --tune=1C).

mamonsu 2.5.1

mamonsu агент мониторинга для сбора метрик операционной системы и Postgres, разработанный Postgres Professional. Главное в новой версии это окончательный переход на python 3 в связи с тем, что в 2020 году уже заканчивается поддержка python 2. Есть и другие обновления. Например, два новых плагина. Первый плагин (он называется точно так же: pg_probackup) позволяет следить за размером каталогов бэкапа, которые хранят WAL и файлы бэкапа, созданные утилитой pg_probackup.

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

Также в состав новых плагинов входят триггеры: для отслеживания статуса ошибки при бэкапе и возраста самой старой подготовленной транзакции соответственно.
Разработчики просят оставлять отзывы, вопросы и предложения по функциональности, по новым метрикам и параметрам на гитхабе mamonsu. Документацию можно смотреть здесь.

В mamonsu есть плагины, которые появляются при установке (в каталоге mamonsu/plugins). Все они перечислены в примере конфигурационного файла. При установке этот файл автоматически подставляется как конфигурационный файл по умолчанию. Метрики в стандартной установке перечислены в середине файла README.rst. Но у пользователя есть еще и возможность самому написать плагин. Структура каждого питоновского файла, собирающего метрики состоит из определённого набора функций.

В блоге Zabbix выложена статья-расшифровка доклада разработчицы Дарьи Вилковой (Postgres Professional) для Zabbix Meetup Online.

dbForge Studio for PostgreSQL v2.3

Это графический инструментарий для работы с SQL в Postgres под Windows: с редактором кода, разноцветным форматированием его, генератором скриптов и профайлером (окна профайлера можно увидеть на скриншотах). Платный (трайл 30 дней). Производитель этой студии а также довольно популярной утилиты dbForge Data Compare for PostgreSQL компания Devart (головной офис в Праге, разработчики в Харькове).

В новой версии революционных изменений нет: например, поддержка PostgreSQL 12 генерация скриптов появились в 2.2, но много удобств добавлено.





Генератор скриптов, который создает соответствующий скрипт в ответ на действия мышью, научился создавать их для: DROP/CREATE TABLE, DROP/CREATE SEQUENCE, DROP/CREATE, CREATE INDEX. Улучшилось форматирование SQL, теперь предложения с CREATE TRIGGER, CREATE INDEX, CREATE SEQUENCE, CREATE TABLE, CREATE VIEW, CREATE MATERIALIZED VIEW, PROCEDURE\FUNCTION выглядят красиво. Профайлер научился показывать план, не исполняя запрос.


pgagroal 0.8.1

В этой версии пулера улучшена работа с системой мониторинга Prometheus: теперь pgagroal указывает серверы, которые отказали, и показывает ошибки на них. Релизы pgagroal выходят часто. В предыдущей в версии 0.8.0 пулер обучился переподключению (failover) и поддержке systemd. В 0.7.0 в конце мая появилось удалённое управление.


pg_dumpbinary 2.2

Новая версия программы Жиля Дароля (Gilles Darold), которая сохраняет дамп в бинарном формате и восстанавливает базу командой pg_restorebinary, приблизилась к поведению самой pg_dump: теперь выгружаются таблицы и последовательности расширений, зарегистрированные функцией pg_extension_config_dump. Подробный чейнджлог релиза здесь. Загрузить можно отсюда.

PostGIS 3.0.2

Вместе с этой вышли и версии 2.5.5, 2.4.9 соответствующих стабильных веток. Работают с PostgreSQL 13 beta2 и ниже вплоть до PostgreSQL 9.5 и с GEOS позже версии 3.6. Исправление ошибок, принципиальных изменений не видно.

pg_probackup 2.4.2

В этой версии утилиты появились пакеты SUSE. Кстати, в разделе Статьи есть план целой серии статей о pg_probackup.

Foreign Data Wrapper for SQLite 1.2.1

Toshiba Software Engineering & Technology Center сообщает о новой версии. Она работает с PostgreSQL 9.6, 10, 11 и 12. Улучшено:
  • добавлен пушдаун Limit/Sort в SQLite;
  • тип SQLite datetime numeric конвертируется в PostgreSQL TimeStamp

FDW поддерживает:
SELECT, INSERT, UPDATE and DELETE на внешних таблицах; транзакции.
Пушдауны:
  • WHERE-предложений;
  • агрегации;
  • ORDER BY;
  • LIMIT и OFFSET (*в случае, когда все таблицы, к которым обращаются, внешние);

Детали есть в репозитории с исходниками.

Статьи


PostgreSQL 14: Часть 1 или июльский разогрев (Коммитфест 2020-07)

Обстоятельная статья, в ней отражены все новые коммиты, а многие из них проиллюстрированы примерами. Причем некоторые относятся к версии 13. Сейчас появились и будут появляться статьи, посвященные отдельным или нескольким новшествам в PostgreSQL 14, но вряд ли появится текст, касающийся стольких коммитов.

На эту же тему, понемножку:
у Хуберта Любашевски (aka depesz) в серии Waiting for PostgreSQL 14:

Пока 3 темы, но продолжение несомненно последует.

Как Lingualeo переехал на PostgreSQL с 23 млн юзеров

Полное название начинается с В карантин нагрузка выросла в 5 раз, но мы были готовы. Статья главного бэкэнд-разработка компании Lingualeo Олега Правдина вызвала интерес слоёв более широких, чем сисадмины PostgreSQL. На момент Postgresso 24 уже 772 комментария при 44К просмотров. Может потому, что в статье много об административных преобразованиях, поиске исполнителей, может из-за того, что при переходе на новую систему сознательно грохнули некоторое количество (примерно 1%) пользовательских данных. Ну и стартовали холивары на темы NoSQL vs классика и логика внутри базы vs логика в приложениях.

Lingualeo это сервис с 23 миллионов пользователей из России, Турции, Испании и стран Латинской Америки, которые учат с его помощью английский, 100 тыс. одновременных пользователей в пике. У пользователей есть свои собственные словари (они и пострадали частично), Джунгли, курсы. Всё это работало на PHP/MySQL. Теперь всю логику перенесли в базу с хранимками на PL/pgSQL.

В статье не густо технических подробностей (обещают целую серию статей в ближайшем будущем), но их можно найти в комментариях под статьёй. Например, вот так там описано новое решение:
  1. фронт дергает ручку Список покупок;
  2. прокси-сервис [на Go, занимается балансировкой запросов к Мастеру и Слйэвам, плюс обеспечивает взаимодействие с внешними сервисами] получает запрос и дергает соответствующую хранимку в базе (в этой точке возможен гибкий роутинг к слэйвам, например);
  3. хранимка формирует ответ в виде json. В ответе есть атрибут с инструкцией для прокси-сервиса: вызови микросервис sms_sending, вот ему json с параметрами;
  4. прокси-сервис выполняет инструкцию;
  5. прокси-сервис отправляет готовый ответ на фронт (п. 4 и 5 могут параллельно выполняться, если независимые).

Нужно:
  1. разработать хранимку (PL/pgSQL) на 50-100 строк;
  2. время разработки и отладки: 1 2 часа;
  3. скорость отклика: 1 2 мсек (если структура данных правильная);

Прокси-сервис отдаёт готовый JSON на фронт.

Коллеги подсказали мне, что, судя по этим сведениям, в Lingualeo на практике применили подход, теоретически обоснованной в таких статьях как Connecting Galaxies: Bridging the Gap Between Databases and Applications (соавтор статьи, которой, увы, нет в бесплатном доступе, Борис Асенович Новиков, автор учебника Основы технологий баз данных) или в более ранней Talking To The Database In A Semantically Rich Way. Суть в том, что несоответствие в моделях данных между объектно-ориентированными приложениями и реляционными СУБД может стать роковым для данных. Чтобы его преодолеть, надо обмениваться не отдельными строками отдельных таблиц, а составными объектами (используя, например, JSON, как транспортный формат).

В статье Lingualeo нет ни слова о полнотекстовом поиске, есть только задача:

Чтобы заработала функция перевода слов по клику, текст надо разделить на слова, выражения и словосочетания. Затем обратиться к словарю и вывести пользователю перевод в новом окошке поверх текста. Бэк передаёт на фронт готовый JSON, в котором текст уже разбит на слова и выражения.

Но в комментарии автор поясняет:

Мы упростили всю систему, исключив rabbit, kafka, elastic search и др. FTS (full-text search) в PG позволяет находить необходимые данные в базе из миллионов документов за 2-3 мсек для наших задач более чем достаточно

реализовал в хранимке токенизацию текстов с иероглифами (когда идет сплошной список иероглифов, без проблемов, и их надо правильно разбить на слова и выражения, словарь прилагается в таблице). Хранимка с рекурсивным CTE, 50 строк, примерно час ушел на разработку. Скорость обработки в 20 раз быстрее, чем скрипт на питоне. И по размеру кода в 10 раз меньше.

Надеемся на разъяснения в грядущих статьях.

Знакомство с pg_probackup. Первая часть

Александр Никитин из БАРС Груп написал статью об этой утилите Postgres Professional. В первой части он рассказывает о резервном копировании. Дальше будет о восстановлении. Вообще запланировано рассмотреть прежде всего 4 темы:
  • создание автономных бэкапов на отдельном сервере
  • создание архива WAL-файлов и создание бэкапов в этом режиме
  • развёртывание реплики из бэкапа и настройка создания бэкапов с реплики
  • различные варианты восстановления;


Путеводитель по резервному копированию баз данных

Владимир Комаров aka hard_sign рассматривает резервное копирование во всех основных СУБД (Oracle, DB2, MS SQL, MySQL, а в эпизодах и MongoDB, Cassandra, Percona Server), в том числе и в PostgreSQL, конечно. В главке об инкрементальном резервном копировании несколько абзацев посвящены pg_probackup.

Эта статья часть мощной серии:
Путеводитель по репликации баз данных
Классификация критичности информационных систем
Распределённые СУБД для энтерпрайза.

Из более ранних есть и остросюжетная: Так что же случилось со Сбербанком?

Why PostgreSQL 13 is a Lucky Release

Джонатан Катц (Johnathan S. Katz, Crunchy Data) справедливо считает, что этот релиз не был решающим прорывом с точки зрения наращивания функциональности, но что это хорошая штука для всех каждый найдёт в нем что-нибудь для себя, из-за чего стоит немедленно проапгрейдиться до PostgreSQL 13.

Прежде всего считает он это сокращение размера индексов (дедупликация b-tree). На демонстрационном примерчике выигрыш в три раза по объему и в два раза по производительности. Далее: вакуум работает побыстрее за счет того, что индексы, опять же, во время чистки таблицы обрабатываются параллельно, при этом число параллельных процессов настраивается. Еще Джонатан отмечает как особо важную фичу инкрементальную сортировку. Напоминаем, что в нашей статье о PostgreSQL 13 эти пункты рассмотрены немного подробней (кстати, выигрыш в объеме индекса у нас тоже в 3 раза), но пунктов там гораздо больше, что преимущество и недостаток одновременно в зависимости от цели читателя.

Avoiding the Pitfalls of BRIN Indexes in Postgres

Джон Порвазник (John Porvaznik, Crunchy Data) для своих примеров генерит табличку с рандомными данными, затем рассматривает структуру индекса BRIN (Block Range INdex), используя расширение pageinspect. На вопрос, заданный себе когда стоит использовать BRIN?, автор отвечает предложением когда таблица large insert-only in-order и дальше останавливается на влиянии каждого звена этой конструкции. Индекс нежный, деликатный. Неожиданное отклонение в каждом из этих звеньев может свести на нет все прелести BRIN, поэтому перед запуском в прод стоит хорошенько промоделировать проект.

How we used Postgres extended statistics to achieve a 3000x speedup

Статья на сайте компании Affinity, известной больше как разработчик инструментов дизайна, рассказывает о том, как их инженеры решили проблему с долгим откликом на их сайте. Проблема была в том, что оптимизатор радикально промазал с оценкой кардинальности ждал одну запись там, где их тысячи. Автор Джереж Ралисон (Jared Rulison) коротко и внятно объясняет важность корреляций при сборе статистики, какие неприятные сюрпризы учёт корреляций может подложить, как оптимизатор может выбрать совсем не оптимальный тип джойна (что и случилось nested loop вместо hash join). Чтобы вразумить оптимизатор надо проделать некоторые дополнительные действия при сборе статистики.

Оценка кардинальности действительно одна из нетривиальных задач. В прошлом выпуске мы упомянули статью нашего коллеги Павла Толмачёва из отдела образования Postgres Professional: AQO адаптивная оптимизация запросов в PostgreSQL. Там рассказывается об об интеллектуальном (с ИИ) модуле (расширении) aqo, который во многих случаях помогает оптимизатору, удачно угадывая кардинальность.

A Crash Course on PostgreSQL for R Users

Союз R и PostgreSQL нечастая тема. В нехитрой статье и примерах используется демонстрационная база Полётов Нью-Йоркских аэропортов (во flights14 > 12 млн записей). Попробуйте демобазу наших аэропортов она побогаче семантически. Расширение plr Джо Конвея (Joe Conway), позволяющее хранить и исполнять пользовательские R-функции в базе, не используется. Автор обходится обычными соединениями при помощи RPostgres. Используется библиотеки Tidyverse, dplyr и другие. Есть полезные ссылки.

Building a recommendation engine inside Postgres with Python and Pandas

Крейг Кирстинс (Craig Kirstiens) из Crunchy Data решил построить движок рекомендательного сервиса прямо внутри PostgreSQL, то есть используя хранимые функции на plpython3u.
Он взял простенький пример движка на Python с демоданными, загрузил данные в Postgres. Там, где в Python был тип DataFrame, Крейг использует массивы Postgres.


Data systems that learn to be better

Эдам Коннер-Саймонс (Adam Conner-Simons) из Computer Science and Artificial Intelligence Laboratory (CSAIL, лаборатория внутри MIT) пишет о проектах со зловещими именами: Цунами (Tsunami) и Bao (BAndit Optimizer).

Цунами основан на теоретической статье The Case for Learned Index Structures (по ссылке только аннотация), написанной в 2017-м профессором MIT Тимом Краска (Tim Kraska) с соавторами и соратниками из Google. Статья тогда наделала шуму в Postgres-сообществе. Там говорилось: идея в том, что модель может выучить порядок сортировки или структуру словарных ключей (structure of lookup keys) и, исходя из этой информации, определять оптимальную позицию записи в индексе или вообще ее необходимость.

Приближается революция? спрашивал Николай Самохвалов. Мало кто верил, что обучающиеся индексы действительно заменят B-деревья, хэш-индексы и Bloom-фильтры. В качестве трезвого взгляда Олег Бартунов, например, приводил исследование, где ИИ работал не лучше интерполяции сплайнами:
The Case for B-Tree Index Structures Томаса Ноймана (Thomas Neumann). Никто из разработчиков PostgreSQL, во всяком случае, не реализовал работоспособные обучающиеся индексы.

Краска, однако, представил проект Tsunami в стенах CSAIL. Он утверждает, что на тестах удаётся достичь выигрыша в скорости исполнения запросов на порядок, а данные можно организовать в наборы обученных индексов, сократив суммарный объем на два порядка (примерно как он и предсказывал в той статье).

Кроме того, с коллективном другого состава под руководством Райана Маркуса (Ryan Marcus) он участвует в проекте Boa (аннотация), где, как утверждается, оптимизатор, полностью интегрированный в PostgreSQL, учится меньше часа на собственных ошибках, после чего составляет план так, что бьёт по производительности опенсорсные и коммерческие СУБД.

А цель CSAIL объединить эти два проекта в один, который будет работать в существующих облачных инфраструктурах, таких как амазоновский Redshift. Скептики не ведутся: любопытно, но я что-то не знаю ни одного, кто бы над этим работал пишет Брюс Момджан (Bruce Momjian). Но Дмитрий Долгов видел сообщения, что о планах реализовать Bao как опенсорсный проект, хотя никакого взаимодействия с Postgres-сообществом пока не замечено.

Образование


Вышла новая английская версия Малютки PostgreSQL: The First Experience

В этом издании примеры на PostgreSQL 12. Загрузить PDF можно бесплатно отсюда. А русская версия здесь.

Облака


Postgres Pro на Azure, mail.ru и Яндексе

Виртуальные машины, с вышедшими в конце августа новыми минорными версиями Postgres Pro, появились в облаке Microsoft Azure. Там есть виртуальные машины Postgres Pro Enterprise и Postgres Pro Standard версий 9.6.19.1, 10.14.1, 11.9.1 и 12.4.1 (виртуальные машины Postgres Pro Enterprise версий 10.14.1, 11.9.1 и 12.4.1 в двух вариантах с ОС Centos и ОС Ubuntu).

Кроме этого, Postgres Pro Standard версий 11 и 12 предлагается в облаке Microsoft Azure в виде образов Docker-контейнеров и в составе виртуальной машины, и в виде самостоятельного контейнера. Немало: 13 приложений на фоне примерно 60, имеющих отношение к Postgres. В том числе их собственных решений, например PostgreSQL Hosting: Fully Managed DBaaS on Azure.

В Яндекс.Облаке стали доступны виртуальные машины с Postgres Pro Enterprise 11.9.1 и 12.4.1. В их составе pg_probackup, CFS, multimaster и прочие Enterprise-возможности, а также установленные и настроенные сервер Zabbix и агент mamonsu. Руководство по созданию и использованию Postgres Pro Enterprise в Яндекс.Облако здесь. Незадолго до этого Postgres Pro в виде DBaaS появилась в облаке Mail.Ru Cloud Solutions пока только с Postgres Pro Standard 11.

У Яндекса есть и своя PostgreSQL Yandex Managed Service for PostgreSQL (кластеры с версиями 10, 11 и 12, а также PostgreSQL 10 для 1C. О производительности 1С в Яндекс.Облаке есть ролик в разделе Вебинары). . Есть довольно внушительный список расширений. Вообще, сравнивать облачные предложения занятие полезное и интересное, но не для этого новостного обзора слишком много вариантов. Плюс облачники обычно не стремятся сразу выставить на общее обозрение адекватную для сравнения техническую информацию.

Announcing pgBackRest for Azure: Fast, Reliable Postgres Backups

Крейг Керстинс (Craig Kerstiens) рассказывает о pgBackRest, который теперь может работать в облаках Azure.

DB-Engines Ranking Trend Popularity

Это рейтинг облачных СУБД по некоторому набору критериев. PostgreSQL примостился за Oracle, MySQL и Microsoft SQL Server. Но если глянуть кривые популярности, то видно, что эти трое стоят на месте (и даже чуть заваливаются), а наш красавец упрямо карабкается вверх (но MongoDB цепляется за пятки).

Вебинары и митапы


#RuPostgre

Ровно в начале учебного года 1 сентября Николай Самохвалов с Ильей Космодемянским начали с Интро новый сезон RuPostgres-вторников. В ближайших стримах главный фокус будет на разработческих темах: великий и ужасный SQL, сложные запросы, JSON, оптимизация производительности, отладка, ORM, GraphQL и т.д. и т.п. Но и админские темы постараются не забывать. Документ с инфо, куда можно вписывать пожелания, здесь.

Вебинар 1С на Postgres в облаке

Yandex.Cloud выложили ролик (около 30 мин, начинается почему-то на 9:35): Марат Мустафин, руководитель Центра разработки компании мудрых советов WiseAdvice (основной партнер Yandex.Cloud по 1С) рассказывает о нагрузочном тестировании (22:00), о требованиях к оборудованию, настройках PostgreSQL (в том числе отключение синхронного коммита) на сетевых и локальных SSD, влияющих на производительность, зависимости выбранного размера дисков на скорость работы, надежность и масштабируемость приложений.

Разворачивалось всё и тестировалось на кластере под Windows в яндексовском Managed Service for PostgreSQL, куда входит и их пулер Odyssey. Версия PostgreSQL 10-я (ведутся работы по переходу на 11-ю). Тесты: 1C:ERP тест-центр и синтетический Тест Гилёва. Тестирование вызывает много вопросов. Про Тест Гилёва Марат так и говорит: результаты слишком неоднозначные, и вообще это лишь начало всестороннего тестирования.

Вебинары 2ndQuadrant

JSON & ARRAY Contemporary PostgreSQL Data Types

Состоялся 2-го сентября. Ведущий Борис нет, не знаю, как произнести его фамилию: Boriss Mejas.

New Features in PostgreSQL 13

Ожидается 16-го сентября, в 19:00. рассказывать будет Питер Айзентраут (Peter Eisentraut)

Конференции


pgDay Israel 2020

Должен состояться уже 10-го сентября в Тель-Авиве.



Предыдущие выпуски:
#23, #22, #21, #20, #19, #18, #17, #16, #15, #14, #13, #12, #11 (спец), #10, #9, #8, #7, #6, #5, #4, #3, #2, #1
Подробнее..

Postgresso 25

09.10.2020 14:15:38 | Автор: admin


Жизнь продолжается. А мы продолжаем знакомить вас с самыми интересными новостями PostgreSQL.


Главное событие


EDB Completes Acquisition of 2ndQuadrant

EDB поглотила 2ndQuadrant. Теперь всё будет под брендом EDB. Руководить будет CEO EDB Эд Бойджан (Ed Boyajian), а великий и ужасный Саймон Риггс (Simon Riggs) из 2ndQuadrant получит титул PostgreSQL Fellow и будет PG-евангелистом и техническим стратегом.

Не будем считать деньги, а напомним о вкладе в сообщество от обеих уважаемых, почтенных компаний (EDB основана в 2004-м, 2ndQuadrant в 2001-м).
Если считать по участникам основных разработчиков PostgreSQL (core team), то счет 2:1 в пользу EDB: Bruce Momjian и Dave Page (PgAdmin) от EDB, против Peter Eisentraut от 2nd Quadrant. Брюс Момджан напомнил о неписанном правиле сообщества: в core team не должно быть больше половины разработчиков из одной компании. А в новом EDB 3 из 5.

Если считать по главным контрибуторам (major contributors) в код PostgreSQL, то маятник качнулся в другую сторону: 5: 3 в пользу 2ndQuadrant Andrew Dunstan, lvaro Herrera,
Petr Jelinek, Simon Riggs, Tomas Vondra против Devrim Gndz, Robert Haas, Amit Langote.
Но у 2ndQuadrant есть ещё и один Заслуженный хакер (hackers emeritus) Marc G. Fournier.

И ещё: Эд Байджан в своей статье на сайте 2ndQuadrant ссылается на COVID-19 как на силу, направляющую пользователей в сторону PostgreSQL, о чём говорится даже в некотором специальном исследовании.

Покупку уже успели обсудить на Postgres-вторниках Николая Самохвалова и Ильи Космодемьянского. Брюс Момджан оценил событие так: в целом положительно, но риски есть. Кроме изменений в core team ещё и минусы консолидации (меньше выбор, слабее конкуренция) и риск того, что процесс пойдёт и дальше: больше шанс, что какая-нибудь крупная компания может захотеть поглотить EDB.

PostgreSQL 13

Это произошло! Почти сразу после релиза-кандидата вышел и официальный релиз.

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

Там же, на Crunchy, есть и статья Грега Смита (Greg Smith) PostgreSQL 13 Upgrade and Performance Check on Ubuntu/Debian: 1.6GB/s random reads. Статья этого уважаемого автора собрала, однако, некоторые ложки дёгтя претензии к методу оценки производительности. В конце статьи мы видим медовый вывод: PostgreSQL 13 на Ubuntu совершенно прекрасен! Я проверил!

О релизе почитать здесь, загрузить отсюда, информация для бета-тестеров здесь.


Статьи


PostgreSQL, a community project

Питер Айзентраут (Peter Eisentraut, 2ndQuadrant то есть уже EDB) пишет внезапно не техническую статью, а предлагает мини-анализ Postgres Success Story он заметил, что после выхода 13-й версии, в блогах и на форумах больше говорили не о версии, а не могли нарадоваться устойчивости сообщества. Причина устойчивости по Айзентрауту такая: из 3 типов опенсорсных проектов
  • ведомых одним человеком (или двумя не многими);
  • ведомых компанией;
  • ведомых сообществом

лишь третий тип устойчив. Причины неустойчивости первых двух переход из одной категории в другую часто бывает разрушителен.

Waiting for PostgreSQL 14 Support for OUT parameters in procedures

Депеш (Hubert 'depesz' Lubaczewski) пишет: Это большое дело! Процедуры появились в PostgreSQL 11 и они смогли реализовать логику базы, когда несколько транзакций в одной процедуре. Но вернуть данные они не могли, сделать SELECT по результатам было нельзя, разве что через RAISE NOTICE. А теперь можно. И демонстрирует на примерах.

До этого в серии ожиданий PostgreSQL 14:

Rename wal_keep_segments to wal_keep_size.

pg_stat_statements: track number of rows processed by some utility commands.

Improvements for handling large number of connections.

Ну и напоминаем ещё раз об Июльском разогреве Павла Лузанова.


Postgres и ИИ


Мы сделали микрообзор некоторых статей на эту модную тему. Такие статьи делятся на две категории: ИИ для оптимизации самого Postgres (в том числе ИИ как подсказчика оптимизатору) с одной стороны, и Postgres как инструмент хранения и работы с данными для машинного обучения (чаще хранения, чем работы) с другой.

На статью об ИИ-оптимизации мы недавно ссылались, сделаем это ещё раз: AQO адаптивная оптимизация запросов в PostgreSQL, автор Павел Толмачёв. Теперь об обработке и хранении данных ИИ.

Changing the Rules on MDM: Data Mastering at Scale [М.Стоунбрейкер]

Отец Postgres Майкл Стоунбрейкер выступил на DataMasters Summit конференции Tamr, что не удивительно: он со-основатель этой компании и её технический директор. Пока можно почитать статью Data Mastering at Scale, по мотивам которой, видимо, и сам доклад.

Он говорит о том, что за ETL (Extract, transform and load, извлечение, преобразование, загрузка) следует собственно Data Mastering (управление мастер-данными), где в данных, скажем, есть несколько Стоунбрейкеров (Майк, Майкл, М.), и надо понять, где настоящий Майкл Стоунбрейкер и оставить его единственную, золотую копию. Раньше соответствующий софт с этими задачами худо-бедно справлялся, но последние годы вместо нескольких источников данных может понадобиться 10 тыс. источников (как у Groupon), 250 баз на 40 языках (Toyota). И в этом случае считает не стареющий душой Майкл Стоунбрейкер на базе правил мастеринг
работать уже не будет, а нужно машинное обучение. Без человека всё равно не обойтись, но стюарты данных будут скорее спецами по выбору ML-моделей, по обучению их. И в заключение ссылается на концептуальную статью The Data Civilizer System, где описана MDM будущего.

Postgres and the Artificial Intelligence Landscape

Это PDF-презентация Брюса Момджана. Он говорит не об ИИ для оптимизации работы базы, а о собственно вычислениях машинного обучения, производимыми над данными, хранящимися в БД. Он приводит код на PL/Perl. То есть все ML-вычисления происходят именно внутри базы (гораздо чаще базу используют только для хранения, а вычисления выносят в приложения на Python или других языках). Вот почему Брюс предлагает использовать базу, и использовать её таким образом:
  • для машинного обучения нужно много данных;
  • бОльшая часть этих данных в вашей базе;
  • почему бы не обучать там, где лежат данные, в базе?
  • ведь возможен бесшовный доступ к актуальным данным;
  • можно сразу что-то делать с результатами работы ИИ (например, коммитить транзакции, если ИИ не считает банковскую операцию мошеннической);
  • ИИ выиграет от возможности транзакций, согласованности, бэкапа;
  • можно использовать сложные типы данных, FTS, GIS, индексирование;
  • Postgres может использовать GPU внутри базы.

Machine Learning with 2UDA

Серия из 7 статей о применении софта 2ndQuadrant 2UDA для машинного обучения. Он работает в среде Orange 3, то есть ориентирован на Python. То есть не внутри базы, используя не функции PL/Python(3)u, а внешние программы. Там есть, например, реализация K-NN тоже внешняя, хотя внутри штатного PostgreSQL есть конструкция GOUP BY "<->" LIMIT K, ускоряющая поиск (см. в этом выпуске статью Рамси о PgRouting и PostGIS)

Machine Learning in PostgreSQL part 1: KMeans Clustering

Герман Резницкий (Hernan Resnizky, Cybertec) рассказывал пару лет назад о KMeans (метод K-средних), реализованных внутри базы на PL/Python(3), расширение plpython(3)u. Модели грузятся как тип bytea. А предсказание K-среднего требует передачи в созданную питоновскую функцию массива массивов:
SELECT predict_kmeans('models','model',1,array[[0.5,0.5,0.5,0.5]]);

Данные брали из ML-репозитрия UCI Калифорнийского Университета в Ирвайне.


Postgres и ускорители


Мы решили в этом выпуске в двух словах рассказать о том, что нового делается в мире кремния о GPU, DPU, Arm-CPU.

Oracle Cloud Deepens HPC Embrace with Launch of A100 Instances, Plans for Arm, More

Эти новости не имеют прямого отношения к Postgres, но тенденции любопытные. У Oracle в облаках есть и база Oracle, и MySQL. Системы DGX A100 Nvidia, конечно, придут в облака прежде всего для ИИ, генерации речи, работы с мультимедиа. Но не только: DGX упоминают и в контексте баз данных: у DGX-1 более 1ТБ памяти, но мы её ещё удвоили. Не потому, что могли. А потому, что многие из наших клиентов обрабатывают огромные графы и должны быстро работать с экстремально большими базами данных, столько памяти им действительно нужно! Об этом же по-русски выжимка той статьи: Oracle Cloud расширяет портфель HPC-решений

DPU

Колумбийский университет ведёт исследовательский проект исследование архитектуры специализированных DPU-процессоров (Data Processing Unit) для повышения производительности и экономии энергии при обработке данных больших объемов. Эта исследовательская группа фокусируется на ускорении запросов к РСУБД. Первая разработанная ими архитектура нацелена на ускорение аналитических запросов к большим наборам данных.

А вообще архитекторы DPU мыслят их как часть триады CPU-GPU-DPU (в том числе и в Nvidia, разумеется.

Arms First 64-bit Cortex-R Chip Adds Computational Storage

Arm представила публике свой первый 64-битный процессор реального времени для хранения данных на уровне корпораций. В нём зашита поддержка микросервисов Linux. Он должен воплотить идею вычисления должны быть поближе к данным. Память в нём устроена так, что ОС может работать прямо в контроллере хранения данных. Процессор может адресоваться к памяти в 1ТБ DRAM. Предполагается, что он будет эффективно работать в том числе с Kubenetes и Docker.

Data processing more than billion rows per second [с GPU]

Кохей Кайгай (Kohei KaiGai, глава компании HeteroDB) повествует на вебинаре (видео пока недоступно) о том, как SSD-to-GPU Direct SQL (реализованный как расширение PostgreSQL) оптимизирует поток данных, несущийся по шине PCIe от хранения к процессорам. Цель ускорение аналитических запросов.


PostGIS


Using Postgres and pgRouting To Explore The Smooth Waves of Yacht Rock
Ещё один неожиданный поворот. Не потому, что речь в этой статье Джона Порвазника (John Porvaznik, Crunchy Data) не о яхтах и камнях, а о музыке для яхт (что-то вроде софт-рока, Beech Boys, видимо), а потому, что рассказывается о расширении pgRouting, которое требует установки PostGIS, и используется обычно для маршрутизации в самом буквальном смысле прокладывании маршрутов на карте. Но с его помощью можно и обходить графы (не используя функции PostGIS вообще). Автор строит замысловатый граф из данных о песнях и их исполнителях и натравливает на него алгоритм Краскала. Графы в статье очень красивы. Результат: лучший музыкант для яхтинга Джеф Паркаро (я не слушал: нет яхты).

Зато Пол Рамси (Paul Rumsey) занимается в майской статье Routing with PostgreSQL and Crunchy Spatial прокладыванием маршрутов по улицам Бостона. Но использует ещё и pg_tileserv и pg_featureserv гошные компоненты их пакета Crunchy Spatial. Кстати, пользуется и "<->" в конструкции ORDER BY, которая радикально ускоряет поиск ближайших соседей.

Для визуализации Рамси использует OpenLayers, а не QGIS, как многие сейчас. Геоданные берёт с Geofabrik.

Spatial analysis with PL/R

Серия из трёх статей ещё 2007 года, зато написанная автором расширения plr Джо Конвеем (Joe Conway, Crunchy Data). Он предлагает использовать R внутри базы во взаимодействии с функциями PostGIS. R пригодится для аналитики пространственных данных. Для примера он строит графики NDVI (Normalized Difference Vegetation Index вегитационный индекс) окрестностей Сан-Диего. R при этом работает с растровыми, а не векторными данными. Берёт их у United States Geologic Survey (USGS), а результаты визуализирует с помощью старинной R-библиотеки получается вполне симпатично.

Иван Муратов о PostgreSQL + PostGIS + TimescaleDB на SDCast #123

PostgreSQL + PostGIS + TimescaleDB хранилище для систем мониторинга транспорта доклад Ивана на PGConf.Russia 2019 (слайды и видео).

PostGIS vs. Geocoder in Rails

Лей Холлидей (Leigh Halliday), автор-гость в блоге pganalyze, разрабатывал приложения на Ruby on Rails и обходился без PostGIS, пользуясь Geocoder. Но овладел всё же PostGIS и теперь сравнивает. В примерах кода на Ruby используется сгенерённая демобаза со 100 тыс. домов и 100 школ. Лей по касательной задевает понятия SRID и измерения расстояний на сфере (о сфероиде речь не идёт), индексирования геоданных в Rails и в PostGIS. С задачей нахождения домов не дальше заданного расстояния от школы и с домами внутри прямоугольника рельсы и PostGIS справляются за примерно одно время. Но только PostGIS подходит для поиска домов внутри заданного многоугольника и в случае, когда добавляется условие на дом: только те, где можно арендовать квартиру недалеко от школы.


Облака


Announcing Crunchy Bridge: A modern Postgres as a service

Crunchy Bridge теперь доступен на AWS и Azure.

AWS Aurora PostgreSQL versions vanish from the mega-cloud for days, leaving customers in the dark

То был позитив. А вот негатив: Грег Клоу (Greg Clough), разработчик, использующий AWS, обнаружил, что некоторые версии AWS Aurora исчезали на прошлой неделе (то есть стали недоступны для разворачивания; уже существующие базы не пропали). Сейчас всё в порядке.

Diary of an Engineer: Delivering 45x faster percentiles using Postgres, Citus, & t-digest

Нильс Дийк (Nils Dijk, Microsoft) рассказывает, как проблема заказчика на analytics data in Hyperscale (Citus) on our Azure Database for PostgreSQL managed service была решена с помощью расширения t-digest Томаша Вондры.

Cloud Vendors as a Barrier

Отнюдь не все опенсорсные вендоры стремятся в облака. Некоторые защищаются от облаковладельцев лицензиями, ограничивающими право использовать их базы в облаках. В как всегда небольшой заметке немало ссылок на интересные статьи по теме.

Через 3 дня Брюс продолжает тему в посте Cloud Vendor Monetization of Open Source. Тема пересекается с темой статьи Питера Айзентраута. Брюс акцентирует разницу между открыто разрабатываемым открытым кодом (как Postgres) и кодом открытым, но разрабатываемым в компании (как MySQL). Но ссылается он на другую статью: Dining Preferences of the Cloud and Open Source: Who Eats Who?. Там есть симпатичный фрагмент о софтовой пищевой цепочке:
ПО ест мир; открытый код ест ПО, облака едят открытый код, и самое актуальное мульти-облака едят облака. Через эту оптику в статье рассматриваются AWS, Hadoop, Pivotal, Red hat. Особенно нагляден, считает Брюс, пример Red Hat, оказавшейся в результате внутри IBM; но облачники могли бы для своего же блага умерить аппетиты и не съедать, а пасти (немного вольно интерпретируя Брюса) опенсорсные компании как дойных коров.


Миграция, апгрейд, интеграция


How we upgraded PostgreSQL at GitLab.com

Речь о масштабном проекте, в котором используются мощные машины с 96 ядер и 624 Гб памяти. 60К пользовательских коннектов к сайту в сек. держит каскад pgbouncer-ов. Приложения написаны на Ruby on Rails.

Using PostgreSQL to Offload Real-Time Reporting and Analytics from MongoDB

Неожиданный поворот: PostgreSQL предлагают использовать как базу с запросами для чтения как аналитическую. При этом база на MongoDB остаётся для пишущих OLTP-запросов. Данные постоянно копируются из MongoDB в Postgres средствами монговского oplog. Обосновывают такое решение тем, что сложные запросы с агрегацией, с многочисленными индексами и разнообразными джойнами в Postgres сочетаются с развитыми средствами работы с JSON.

Статья лежит на сайте Rockset, и в конце статьи говорится: если уж вы решили выгрузить аналитику и отчёты из MongoDB, но вам нужно серьёзное масштабирование, а данные слабо структурированы, то стоит подумать насчет бессхемных баз реального времени Elasticsearch и Rockset. Они умеют ускорять запросы индексами, а Rockset поддерживает полноценный SQL и умеет делать джойны.


Разное


Морской бой на PostgreSQL

Статья Владимира Турова aka Firemoon. Подробней не на Хабре, а здесь.

Для вывода используется оператор RAISE, который для psql выводит сообщение с префиксом уровня логирования. Избавиться от него не получится, но это не мешает игре.

К сожалению, в PostgreSQL нет планировщика, который бы запускал процедуру по расписанию. Так как проблема находится в серверной части игры, то ее можно решить написанием shell-скрипта, который каждую секунду будет вызывать хранимую процедуру загрузки логов.

Планировщик, вообще-то, есть: pgpro_schedeler в Postgres Pro Enterprise. Код самого боя лежит в репозитории.

Знакомство с pg_probackup. Вторая часть

Александр Никитин из БАРС Груп опубликовал продолжение. В первой части установили pg_probackup, создали и настроили экземпляр, сняли полный и инкрементный бэкапы, научились просматривать и изменять конфигурацию экземпляра. Получили список бэкапов, написали скрипт для резервного копирования кластера и отправки результатов последней операции по снятию бэкапа в систему мониторинга.

Темы второй части:
PITR как хранить копии журналов предварительной записи, чтобы иметь возможность восстановления на произвольный момент времени (Point-in-time recovery); рассматриваются режимы DELTA, PAGE и самый интересный PTRACK, когда создается карты измененных блоков в базе данных.

Вторая тема (задача): снятие резервные копии с реплики. Нужно ли снимать бэкапы с мастера, ведь можно снять читающую нагрузку с мастера и переложить её на реплику? (спойлер: можно, но осторожно).

Следующая часть будет посвящена восстановлению из бэкапов: варианты восстановления, PITR, частичное и инкрементное восстановление.


Вебинары и митапы


Вебинар по JSONB Олега Бартунова



17-го сентября в новой студии Postgres Professional Олег Бартунов провёл вебинар Roadmap for JSON in PostgreSQL: What's Next? Вебинар был ориентирован на англоязычную аудиторию. Примерно треть эфирного времени пришлась на вопросы и ответы. Вопросов было очень много. Видео будет выложено позже.

Postgres-вторники

Теперь они будут не каждый вторник, а через один. Зато дополнятся англоязычными Postgres-Thursdays. Обещано, что в четвергах поучаствуют весьма известные персоны.
На YouTube;
в Zoom (ссылка теперь каждый раз новая);
планы, детали.


Релизы


dbForge: Data Compare for PostgreSQL v.3.3 и Schema Compare for PostgreSQL, v1.0

У Devart, известной dbForge Studio for PostgreSQL и Data Compare for PostgreSQL, появился новый продукт: Schema Compare for PostgreSQL v1.0. Пока он ориентирован больше на Amazon Redshift, умеет сравнивать схему PostgreSQL со схемой Redshift и помогает переезжать с первой СУБД на вторую (подробней здесь). В блоге Devart большое количество скриншотов, и сказано, что PostgreSQL, Amazon RDS, Azure PostgreSQL поддерживаются частично. Но обещано развитие в направлении PostgreSQL.

Параллельно вышел релиз новой версии dbForge Data Compare for PostgreSQL v.3.3 с поддержкой PostgreSQL 13 и с управлением скриптами предварительного и последующего выполнения (Pre & Post Script execution functionality).

pgtools

Этот инструмент дебагинга приложений, работающих с базами данных, в реальном времени показывает события базы данных, вызванные работой приложения. pgtools использует для перехвата событий базы триггеры и триггерные функции. Серверная часть написана на Python3, клиентская на vue.js. Пока находится ещё в стадии разработки, поэтому автору Лукасу Лёффлеру (Lukas Loeffler) нужна и важна реакция, советы и найденные ошибки.

PostgresDAC 3.9

PostgresDAC это набор компонентов для доступа из RAD Studio (Delphi и C++Builder)/FreePascal/Lazarus к разным Postgres-ам: PostgreSQL, EnterpriseDB, Amazon RDS, PostgresPro, и Heroku Postgres.

Главное в этой версии поддержка PostgreSQL 13 и RAD Studio 10.4.1: добавлены клиентские библиотеки v13 и библиотеки dump & restore v13 (pg_dump.dll, pg_restore.dll).

Загружать отсюда.

Pgpool-II 4.1.4

А точнее: 4.1.4, 4.0.11, 3.7.16, 3.6.23 и 3.5.27. О релизе можно почитать здесь, а скачать отсюда.

pg_probackup 2.4.4

Новое: появились пакеты для SUSE 15.2 и поддержка PostgreSQL 13. Если пропустили, то напоминаем, что в подразделе Разное раздела Статьи есть о второй части статьи из серии об этом пакете.


Конференции


HighLoad++

Должна состояться 9 и 10 ноября 2020 в Офлайн Сколково.
Конференция HighLoad++ НЕ будет перенесена в онлайн. В случае, если регулирующие органы не разрешат проводить конференцию 9 и 10 ноября, она будет перенесена со всеми обязательствами и партнёрствами на 1 и 2 марта 2021 года. Для тех, кто воспользуется бронью организаторов в гостинице в Сколково, бронь будет перенесена автоматически.




Предыдущие выпуски:
#24, #23, #22, #21, #20, #19, #18, #17, #16, #15, #14, #13, #12, #11 (спец), #10, #9, #8, #7, #6, #5, #4, #3, #2, #1
Подробнее..

Postgresso 26

13.11.2020 14:18:57 | Автор: admin


Жизнь продолжается. А мы продолжаем знакомить вас с самыми интересными новостями PostgreSQL.


Пополнение в Core Team

Напоминаем о неписанном правиле сообщества: в Core Team не должно быть большинство из одной компании. После слияния-поглощения EDB 2ndQuadrant 3 из 5 участников Основной Команды оказались коллегами по EDB. К счастью, никого не сократили, а добавили двух достойных: Андреса Фройнда (Andres Freund, Microsoft, Citus) и Джонатана Каца (Jonathan Katz, Crunchy Data).

Любимые области Андреса Фройнда: репликация, производительность и масштабируемость (смотрите три недавние статьи на эту тему, ссылки в нашем разделе Статьи. Производительность), хранение.

Джонатан Кац (Jonathan Katz, Crunchy Data) занимался патчами и ревью, но больше концентрировался на разработке и поддержке сайта, выпуске релизов и прочей сопутствующей, но необходимой деятельности. Он вообще важный человек: председатель совета директоров Ассоциации PostgreSQL в США (United States PostgreSQL Association) и директор Ассоциации PostgreSQL-сообщества Канады (PostgreSQL Community Association of Canada), которая выступает как юридическое лицо сообщества.

Прекрасное, взвешенное решение. Впрочем, не все с этим согласны: Альваро Эрнандес (lvaro Hernndez Tortosa если полностью) поздравил новоизбранных (непонятно кем и непонятно как по его мнению) и предложил задуматься над следующими 10 проблемами управления сообществом:
Влияние компаний:
  • 40% из Core Team были из одной компании, теперь 43%, 71% из двух;
  • 100% из всего лишь 4 компаний.

Многообразие (diversity):
  • 100% это белые мужчины;
  • 100% из США или Европы;
  • все кроме одного работают в американских компаниях.

Демократия:
  • членов Core Team назначают члены Core Team;
  • срок неограничен, четверо являются членами уже больше 15 лет.

Прозрачность:
  • процессы выбора членов и кандидатов, критерии выбора и пр. суть большой секрет;
  • заседания секретны;
  • стратегии (policies) объявляются, а не обсуждаются в сообществе.

Альваро предлагает высказаться. И Ханс-Юрген Шёниг (Hans-Jrgen Schnig) высказывается:
Никогда не замечал и тени расизма при принятии патчей. Может и дальше будем продолжать как было думать о компетентности, а не о расе, гендере или о чём там? У нас с этим никогда не было проблем. Так зачем проблему создавать? Клаус Расмуссен (ClausRasmussen) ещё решительней: зачем нам этот crap с идентичностями? У нас технологическое сообщество, а не Liberal_arts_college. Желающие могут запастись попкорном и следить за дискуссией. Этот текст обсуждается также здесь.

Я опустил детали в обращении Альваро. Ещё одна из упомянутых им проблем (существующих с точки зрения Альваро): Core Team это центральный орган проекта. А юридически проект представляет Postgres Association of Canada, определяя в том числе интеллектуальную собственность: доменные имена, торговые марки и прочее. Как бы чего не вышло.

CF-новость

Анастасия Лубенникова из Postgres Professional стала распорядителем текущего коммитфеста. В этом ей помогает Георгиос Коколатос (Georgios Kokolatos).

Новости PG-этики

А ещё Анастасия входит в Комитет по этике (Code of Conduct Committee) сообщества (а Илья Космодемьянский вышел из комитета).

Кстати, благодаря то ли Альваро, то ли общему настроению, Комитет по этике объявил вакансии: нужны люди из разных стран и разных народов, чтобы отразить многообразие PostgreSQL-сообщества. Пишите на coc@postgresql.org

Документация к PostgreSQL 13.0


The PostgreSQL Global Development Group объявила о доступности русской документации к версии 13. Перевод на русский язык компания Postgres Professional. Официальная страница русскоязычной документации.

Обучение


DEV2: Разработка серверной части приложений PostgreSQL 12. Расширенный курс.

Новый курс продолжительностью 4 дня. В нём:
  • понимание внутренней организации сервера;
  • полное использование возможностей, предоставляемых PostgreSQL для реализации логики приложения;
  • расширение возможностей СУБД для решения специальных задач.

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

Статьи


Масштабируемость и производительность


Measuring the Memory Overhead of a Postgres Connection

Андрес Фройнд (тот самый, кто только что обосновался в PostgreSQL Core Team) опубликовал серию из 3 статей о производительности PostgreSQL при большом числе соединений. Они дублируются в блоге Citus и в блоге Microsoft (пока 20 лайков, 2 подписчика).

В статье об издержках памяти начинается с популярного мотива а если бы треды, а не процессы? Спойлер Андреса: если аккуратно померить, то издержки меньше 2 мебибайта. А неаккуратно это при помощи top и ps.

Для более тонких замеров памяти Андрес использует системные /proc/$pid/status и /proc/$pid/smaps_rollup. Так можно увидеть значения VmRSS, VmRSS, RssAnon, RssFile, RssShmem если вы не знали, что это, то из статьи узнаете и поймёте, почему они важны. Чтобы не обмануться с причиной перерасхода памяти, он замеряет с включенным и отключенным huge_pages. Ещё: надо помнить о copy-on-write при форке процесса.

Analyzing the Limits of Connection Scalability in Postgres

Андрес исследует узкие места с тем, чтобы далее предложить путь их решения, и аргументирует не только из общих соображений, а с примерами и листингами. Раздувание кеша (cache bloat) тоже (как и оверхед при форке) не критично. Управление work_mem тоже удовлетворительно. А собака зарыта в куче снэпшотов: функция GetSnapshotData() дорогая и вызывается часто. Вывод: надо менять саму модель соединений (connection model), а может и модель исполнения запросов (query execution model). А от себя добавим: эта тема более, чем активно обсуждалась в рассылке hackers. Более того: в Postgres Professional давно ведутся разработки в этом направлении. Начиная с 12-й версии в Postgre Pro Enterprise Edition есть встроенный пул соединений. Это не совсем то, что сделал Андрес, но это тоже в тему масштабируемости клиентских соединений.

За диагностической 2-й статьёй следует 3-я конструктивная: предложения Андреса уже в форме патчей, которые должны войти в версию PostgreSQL 14:

Improving Postgres Connection Scalability: Snapshots

Пересказывать эту статью в паре абзацев, кажется, бессмысленно. Даём ссылки на серию патчей Андреса (все они начинаются с snapshot scalability: здесь опускаем):
Dont compute global horizons while building snapshots
Move PGXACT->xmin back to PGPROC
Introduce dense array of in-progress xids
Move PGXACT->vacuumFlags to ProcGlobal->vacuumFlags
Move subxact info to ProcGlobal, remove PGXACT.
cache snapshots using a xact completion counter
(Об этом также здесь)

Другую серию из 3 статей в жанре от 8.3 и до 13 опубликовал Томаш Вондра (Tomas Vondra, 2ndQuadrant то есть EDB).

OLTP performance since PostgreSQL 8.3

В этой статье Томаш сначала объясняет замысел серии: почему начал с 8.3, почему именно эти тесты, зачем ему тестировать полнотекстовый поиск, на какой машине тестировать. Он не ставит цели сверхкорректного сравнения, это скорее упражнение для лучшего понимания PostgreSQL. До 8.3 он уж слишком отличался от нынешнего, охват и так недурен: 12 лет. А машина обычный офисный компьютер.

В 1-й статье серии Томаш исследует производительность OLTP на bgbench, взятой из 13-й версии, scale 100 (1.6 ГБ), 1 000 (16 ГБ) и 10 000 (160 ГБ). Клиенты от 1 до 256. Хранение NVMe SSD / SATA RAID; режимы: read-only (pgbench -S) / read-write (pgbench -N)

Графики с NVMe SSD ведут себя прилично: производительность в основном монотонно растёт с номером версии. А вот с SATA творятся чудеса: c SATA RAID в режиме чтения некоторые флюктуации и, похоже, регресс в версии 9.6. А вот на записи-чтении грандиозное ускорение с версии 9.1 в 6 раз!

Томаш уверен, что постгрессистам придут в голову блестящие идеи, как эффективней использовать ресурсы железа. Патчи по улучшению масштабированию соединений или патч по неволатильным буферам WAL тому пример. Можно ждать радикальных улучшений в хранении (более эффективный формат файлов на диске, использование прямого ввода-вывода, например), более эффективные индексы.

TPC-H performance since PostgreSQL 8.3

Для измерения производительности на аналитических нагрузках Томаш запускал бенчмарк TPC-H (его ещё называют бенчмарком принятия решений decision support), получал результаты, которые можно анализировать ещё очень долго, нарисовал красивые графики, и сделал свои выводы в меру отпущенного на это времени.

В TPC-H 22 запроса на 3 наборах данных: малом, среднем и большом. Томаш гоняет их на версиях от 8.3 до 13, да ещё и то включает, то отключает параллелизм. Коэффициенты масштабирования (scale factor) он выбирает такие: 1 (цель поместиться в shared-buffers), 10 (в память) и 75 (не поместиться в память). Комбинаций море, для анализа простор. Иногда автор действительно опускается до отдельных запросов и анализирует причины странного поведения. Кривая производительности немонотонно меняется с версией, а по отдельным запросам скачет совсем неожиданно. Причина простая: планировщик и оптимизатор умнеют с новыми версиями за счёт новых планов и/или за счет новых способов использования статистики, но оборотная сторона промахи: неверный выбор плана из-за плохой статистики, оценок стоимостей или других ошибок. Примерно то же и с параллелизмом: появляются новые планы, но если стоимости и оценки расходятся с реальностью, выбираются планы, хуже старых, последовательных.


Диаграмма из статьи TPC-H performance since PostgreSQL 8.3. Можно было поместить в наш раздел Прекрасное.

Full-text search since PostgreSQL 8.3

В преамбуле Томаш рассказывает историю FTS в PostgreSQL, которая началась с Олега Бартунова и Фёдора Сигаева лет за 20 до основания Postgres Professional. Далее Томаш сетует на отсутствие индустриальных стандартов тестирования полнотекстового поиска и обращается к собственным ресурсам ПО: в незапамятные времена он сочинил утилиту archie парочку питоновых скриптов, которые загружают архивы переписки PostgreSQL, превращая их в базу, которую можно индексировать, в которой можно искать тексты. Сейчас в таких архивах около миллиона строк 9.5 ГБ не считая индексов. В качестве тестовых запросов он взял 33 тыс. реальных поисковых запросов к архиву на сайте PostgreSQL.org.


Фёдор Сигаев и Олег Бартунов. Фотография из статьи Full-text search since PostgreSQL 8.3

Запросы были разного типа, но для статьи взял вот такие с tsvector, придуманным ещё Бартуновым и Сигаевым:
SELECT id, subject FROM messages WHERE body_tsvector @@ $1SELECT id, subject FROM messages WHERE body_tsvector @@ $1ORDER BY ts_rank(body_tsvector, $1) DESC LIMIT 100


Кроме того Томаш тестировал влияние индексов GIN и GiST. Оба запроса с использованием GIN дают огромный скачок в производительности в 4 с лишним раза! Томаш благодарит за это Александра Короткова и Хейкки Линнакангас (Heikki Linnakangas), придумавших патч Improve speed of multi-key GIN lookups. А вот если использовать GiST, то ничего хорошего вообще не будет. А будет плавная деградация. Почему ж никто не жаловался? вопрошает автор и предполагает, что вместе с апгрейдом версий многие апгрейдили и железо, и это маскировало эффект. Или просто не использовали GiST для текстового поиска.

Олег, Теодор [Фёдор] и их коллеги напоминает Томаш работали над более мощными вариантами GIN-индексов VODKA и RUM [примечание редакции: об индексах RUM, о том, чем они лучше GIN, о расширении rum можно почитать здесь. Про водку не будем :)]. Это как минимум поможет некоторым типам запросов. Особенно автор надеется на улучшение поддержки новых типов полнотекстовых запросов, так как новые типы индексов спроектированы для того, чтобы ускорить фразовый поиск (см. там же).

Книжечки

Кстати, о текстовых файлах и поиске в них. Вот 196640 книг (файлов) в текстовом формате. Их, скорее всего, будут использовать для обучения больших сетей, но можно их, скажем, использовать и в каких-нибудь тестах производительности текстового поиска или ещё каких-то манипуляций текстом. Собирали тексты энтузиасты с the-eye.eu (почему-то недоступного честному пользователю из РФ).

PostgreSQL 14: Часть 2 или в тени тринадцатой (Коммитфест 2020-09)

Эта статья Павла Лузанова из отдела образования Postgres Professional и о производительности тоже: постольку, поскольку патчи, принятые на этом коммитфесте, имели отношение к производительности (о патчах Андреса, которые он упоминал, там тоже есть). Это, как и Часть 1 (Коммитфест 2020-07), MUST READ для тех, кто следит за технологическими новшествами PostgreSQL без IMHO.

Жизнь в PostgreSQL


памяти Джона Хортона Конвея, умершего от COVID-19

Открывает эту мемориальную подборку ссылок недавняя статья Егора Рогова: Жизнь на PostgreSQL

Некто Сергей aka ildarovich делает это на языке запросов 1С, а точнее одним запросом: Игра Жизнь в одном запросе

А вот на C#: Как ускорить игру Жизнь в сто раз, в комментариях есть SQL-код.

На JS, огромная статья, очень красивая визуализация: Эволюционирующие клеточные автоматы

Кстати, о Конвее: Джо (Joe), однофамилец классика клеточных автоматов (в прошлом выпуске мы ссылались на статью 2007-го года про то, как использовать PL/R для GIS) теперь, в начале ноября 2020, пишет на тему сверх-актуальную:

Election Night Prediction Modeling using PL/R in Postgres

Он использует пакеты mvtnorm (3 алгоритма нормального распределения), politicaldata (специальные тулзы для сбора и анализа политических данных) и tidyverse (разные средства анализа данных). Для развлечения Джо предлагает разобраться в немалом количестве строк кода, создаёт свой тип данных и ещё предлагает придумать SQL-запросы в качестве упражнения.

Релизы


PostgreSQL 13.1

А также 12.5, 11.10, 10.15, 9.6.20 и 9.5.24. В новых версиях исправлены обнаруженные баги, в том числе связанные с безопасностью. Сейчас мы не будем на них останавливаться. Они описаны на этой странице.

OpenGauss 1.0.1

Сотрудник Huawei Вадим Гусев сообщает на хабре о появлении openGauss: новая СУБД от Huawei для нагруженных enterprise-проектов прибавила в функциональности

Это форк PostgreSQL, опенсорсный вариант проприетарной GaussDB, который работает на x86 и китайских процессорах Kunpeng 920, у которых архитектура ARM64 (к слову: напоминаем, что ARM ltd куплена Nvidia), то есть мы можем предположить курс на китайское импортозамещение (в нише ARM у нас не Эльбрусы, а Байкалы).
Как утверждают создатели, у OpenGauss гибридная ориентация в духе HTAP, и она многое умеет :
  • колоночное хранение;
  • in-memory engine;
  • развертывается решение как в контейнерах, так и на физических серверах;
  • ИИ (глубокое обучение с подкреплением в сочетании с эвристическими алгоритмами) рекомендует параметры.;
  • инкрементальное резервное копирование;
  • Standby на удаленной площадке в синхронном или асинхронном режиме (до четырех реплик на физическом уровне).

В статье с длинным интернациональным списком авторов (фамилии от индийских до русских, китайцы в меньшинстве) оценивается производительность на TPC-C.

Database Lab 2.0

Николай Самохвалов и Артём Картасов из Postgres.ai (Артём делал бОльшую часть кода) на Постгрес-вторнике 3 ноября рассказали (за полтора часа) о Database Lab 2.0 новой, сильно отличающейся версии своей среды для тестирования и разработки с тонкими клонами (при клонировании копируются только измененные блоки).

Новое:
  • поддержка RDS и других облачных Postgres-сервисов;
  • физическое развертывание с нативной поддержкой WAL-G;
  • декларативное развертывание;
  • управление снэпшотами, политики снэпшотов;
  • предобработка данных (анонимизация);
  • time travel для диагностики, контроля изменений, быстрого точечного восстановления;
  • оптимизация SQL на новом уровне: serverless EXPLAIN и бот-помощник для оптимизации;
  • 100% покрытие миграций БД (изменение схемы) автоматическими тестами на полноразмерных копиях БД;
  • регрессивные тесты;
  • поддержка docker-имиджей для Postgres 9.6, 10, 11, 12 и 13; по умолчанию в них расширения Timescale, Citus, PoWA и много других, а также большинство расширений, поддерживаемых Amazon RDS;
  • документация сильно расширена.


pg_statement_rollback 1.0

pg_statement_rollback это расширение Жиля Дароля (Gilles Darold), Жульена Руо (Julien Rouhaud) и Дэйва Шарпа (Dave Sharpe), которое реализует в PostgreSQL откат транзакции на уровне оператора (server side rollback at statement level for PostgreSQL) как в Oracle или DB2. Это значит, что при ошибке в выполнении оператора его результаты не видны как будто оператора и не было. При этом результаты операторов, выполненных в транзакции до этого, не теряются. В PostgreSQL это можно было сделать только на клиенте, в psql, например:
\set ON_ERROR_ROLLBACK on

Теперь всё будет работать на сервере таким образом, как будто для каждого оператора серверу посылаются
SAVEPOINT autosaveиRELEASE SAVEPOINT autosave

а такая роскошь раньше могла сказаться на производительности. Авторы дают результаты тестов TPS-B и честно рассказывают о проблемах.

pgbitmap 0.9.3

Бета-релиз расширения pgbitmap, доступно на pgxn и github.

Это расширение Марка Манро (Marc Munro) создаёт тип pgbitmap с полным набором функций, операторов и агрегатов. Он отличается от стандартных типов Postgres bit и bit varying тем, что строка не начинается с нулевого бита и тем, что набор операций намного богаче. Этот тип разрабатывался под Virtual Private Database для управления привилегиями. В этом релизе исправлены ошибки, он считается релизом-кандидатом. Сейчас открытых багов не осталось присылайте, если найдёте.
Документация здесь.

pgpool-II 4.2 beta1

В новой версии:
  • улучшено и упрощено конфигурирование логирования;
  • добавлен новый режим кластера: snapshot_isolation_mode, который гарантирует не только модификацию данных нескольким инстансам, но и согласованность по чтению;
  • поддержка LDAP-аутентификации между клиентом и Pgpool-II;
  • импорт SQL-парсера PostgreSQL 13.

и прочее, о чём можно прочитать в Release notes.

Загрузить можно отсюда.

pg_activity 1.6.2

pg_activity это интерфейс в стиле top для мониторинга бэкендов PostgreSQL в реальном времени. Поддерживается Бенуа Лабро (Benoit Lobrau, Dalibo Labs). В нём можно:
  • настраивать частоту обновления;
  • переключаться между тремя представлениями запросов: исполняющиеся/ждущие/блокирующие;
  • сортировать по PostgreSQL-метрикам: READ/s, WRITE/s


Зависимостей теперь мало. Работает на Python 2.6+. Исходники здесь.

pgcenter 0.6.6

На гитхабе Алексея Лесовского (Data Egret) появилась новая версия. В ней:
  • рейтинги запросов адаптированы к версии PostgreSQL 13;
  • тайминги операторов адаптированы к версии 13;
  • надо проапдейтить конфигурацию travic-ci: отключить skip_cleanup; проапгерйдить Go до версии 1.14.


pglogical 2.3.3

Появилась поддержка PostgreSQL 13. Загружать отсюда. Чейнджлог недоступен, за информацией велено обращаться к info@2ndQuadrant.com.

repmgr 5.2.0

Добавлена поддержка PostgreSQL 13. Из изменений:
  • новая опция --verify-backup запускает утилиту pg_verifybackup после сканирования реплики, чтобы убедиться в консистентности скопированных данных (только для PostgreSQL 13 и позже);
  • у failover_validation_command появились новые параметры и конфигурационная опция always_promote для управления промоутированием ноды в случае, когда метаданные repmgr уже неактуальны;
  • поддержка PostgreSQL 9.3 прекращена.


Есть и другие изменения, о которых можно узнать здесь. Сорсы находятся здесь, а инструкции по инсталляции здесь.

Прекрасное


Популярность баз 2006 2020

Скриншоты не передадут гипнотической мощи этой динамической инфографики от DB weekly. Это кино увлекательно, познавательно воодушевляюще и даже чуть-чуть отрезвляюще в то же время.



а через 14 лет популярность PostgreSQL выросла более, чем в 2 раза:



Postgres Observability

Интерактивный шедевр наглядности & информативности (этот скриншот в подмётки не годится). Автор Алексей Лесовский из DataEgret.



Конференции


Highload++

Внимание: переносится! Новые даты конференции 17 и 18 февраля 2021 года!

Ибица 2020 зачеркнуто 2021

Одна из самых любимых PG-народом конференций Postgres Ibiza 2020 должна состояться в 2021 году 23-25-го июня (дата предварительная). Следите за новостями на pgibz.io или на сайте FUNDACIN POSTGRESQL сообщества с испаноязычным уклоном. Про Бали пока не слышно.

Postgres Build 2020

Виртуальная европейская конференция по PostgreSQL, посещение бесплатное. Фокус на кейсы реальных клиентов. Пройдёт 8-9 декабря 2020 он-лайн. Twitter и LinkedIn: #postgresbuild.
Подробнее..

Postgresso 27

31.12.2020 04:15:41 | Автор: admin


Ну и год выдался! Подходит к концу. 21-му надо изрядно постараться, чтобы стать хуже. Но он надеемся стараться не будет. А жизнь продолжается. И мы продолжаем знакомить вас с самыми интересными новостями PostgreSQL.

Но сначала поделимся воспоминаниями: как проводил время на хабре отдел образования компании Postgres Professional:
  • Начнём с того, что под рукой с Postgresso. Из фонового и иногда побочного занятия Postgresso сместился к центру, стал новостным каналом со стабильной периодичностью примерно месяц. Мы отказались от плоского формата большой простыни с большим списком релизов и статей по 3-5 строчек на каждую. В 21-м продолжим экспериментировать, но от периодичности не откажемся.
  • Наш коллективный труд PostgreSQL 13. Чертова дюжина. Первый (задержка в 37 минут после заморозки) и самый полный обзор возможностей 13 версии. Далее последовали обзоры коммитфестов: Июльский, Сентябрьский и Ноябрьский Павла Лузанова. Эта практика 20-го года будет продолжена и в 21-м. Мы часто сами на них ссылаемся а как не сослаться? Они действительно информативны.
  • Жизнь в PostgreSQL и в Postgresso 26 подборка других реализаций Жизни памяти Джона Хортона Конвея, умершего от COVID-19.
  • Автор статьи Серверное программирование на человеческом языке, очень понравившейся хабр-читателям Иван Панченко. Мы помогали Ивану в подготовке статьи.
  • Сотрудник нашего отдела образования Павел Толмачёв написал для хабра статью о модуле aqo. Тема непростая, а тема использование ИИ для оптимизации запросов актуальна, а станет ещё актуальней.
  • К тому же бОльшая часть статей была переведена на английский (спасибо Елене Индрупской за титанический труд). Это серии очень глубоких погружений Егора Рогова Locks in PostgreSQL (ru), WAL in PostgreSQL (ru), MVCC in PostgreSQL (ru) и Indexes in PostgreSQL (ru). Кроме того переведён ещё десяток статей, наиболее интересных для англоязычной аудитории. Некоторые из этих статей попадали в англоязычные обзоры самых интересный статей.


Релизы



Вышла Postgres Pro Standard 13

18 декабря 2020 года компания Postgres Professional выпустила новый релиз Postgres Pro Standard 13.1.1. Это первый из тринадцатых релизов Postgres Pro.

Среди новых возможностей:

Новое расширение pgpro_pwr (или PWR, читается как power). Это расширение позволяет получать отчёты по нагрузке, полезные для выявления наиболее ресурсоёмких операций в базе данных. Оно умеет использовать данные расширения pgpro_stats, предназначенного для сбора статистики выполнения SQL-операторов и подсчёта статистики событий ожидания. pgpro_stats обновлено. В январе мы опубликуем на хабре отдельную статью о PWR.

Появилась поддержка операционной системы ОСнова 2.0. Также исправлены ошибки в PostgreSQL 13.1. Среди этих исправлений устранение уязвимостей CVE-2020-25694, CVE-2020-25695 и CVE-2020-25696 (6 патчей сотрудников Postgres Professional).

Postgres Operator v1.6.0

Релиз поддерживает последнюю PostgreSQL 13 и новый образ Spilo 13 (спило слон по-грузински), в котором имеется Patroni 2.0 (но последняя версия Patroni на сегодня 2.0.1). Апгрейд ещё не автоматический, но сильно упростился. Проще стало развертывание pgBouncer на репликах. Подробности в чейнджлоге и в доке.

Pgpool-II 4.2.0

Изменения:
  • в этом релизе теперь во всех образцах файла pgpool.conf путь к сокетам /var/run/postgresql;
  • Используется единственный сегмент разделяемой памяти для всех разделяемых переменных родительского процесса pgpool;
  • при старте убиваются существовавшие до того файлы сокетов watchdog

Загрузить можно отсюда.

pg_timetable: Advanced PostgreSQL Scheduling

Это шедулер, написанный на Go разработчиками Cybertec и работающий как отдельное приложение (для сравнения: pgpro_scheduler выполнен как расширение). Он умеет выполнять задания, состоящие из нескольких разнородных действий, например:
  • начать транзакцию;
  • записать в лог;
  • загрузить файл;
  • импортировать файл;
  • запустить агрегирование;
  • закоммитить транзакцию.

pg_timetable на гитхабе.

Новый начальник Коммитфеста


Масахико Савада (Masahiko Sawada, NTT) стал распорядителем нового Коммитфеста (предыдущий координировала Анастасия Лубенникова)

Статьи


PostgreSQL 14: Часть 3 или ноябрьское затишье (Коммитфест 2020-11)

Это изменения после ноябрьского коммитфеста, последнего в 2020. Павел Лузанов сам предлагает обратить особое внимание на вопросы:
  • Не пора ли увеличивать wal_buffers?
  • Можно ли перегружать хранимые подпрограммы по OUT-параметрам?
  • По умолчанию pg_stat_statements собирает данные о 5000 запросов. Как понять много это или мало?
  • Что будет, если в операционной системе обновится библиотека libc?

Текст огромный, так как список изменений полный. Продолжение следует после январского коммитфеста.

Обзор операторов PostgreSQL для Kubernetes: Часть 1: наш выбор и опыт и Часть 2: дополнения и итоговое сравнение"

В первой части Николай Богданов в блоге компании Флант, советовал начать с доклада на Highload++ своего коллеги Дмитрия Столярова, где тот знакомит с общими принципами работы баз данных в Kubernetes (K8s). Николай же формулирует 6 основных требований со стороны K8s и рассматривает операторы:
  • Stolon. Этот довольно популярный отказоустойчивый кластер интегрирован в K8s. Но Stolon не подошёл, так как первое же (деплой из Git и с Custom Resources) из тех кубернетовских требований не удовлетворено (нет Custom).
  • Crunchy Data PostgreSQL Operator разработка нашего старого postgres-знакомого CrunchyData (автор называет молодым стартапом) богат фичами, но он оттолкнул несоответствием принятым в K8s стандартным возможностям работы с ресурсами.
  • Zalando Postgres Operator понравился больше всего. И возможностей много, и развивается быстро, и соответствует look & feel в глазах истых кубернетчиков.

Дальше Николай начинает работать с Crunchy Data PostgreSQL Operator, делится впечатлениям. А они не столько радужны, как хотелось. Список проблем и их решений, а также план миграции прилагаются.
Во второй части обзора, вышедшей 13-го ноября, добавились ещё два K8s-оператора:
KubeDB и
StackGres.
В результате появилась сводная таблица матрица имеющихся возможностей этих 5 операторов. Но сердце автора уже прикипело к Zalando, он объявлен лучшим вариантом для тру кубернетчика.

What are table access methods, and what is their importance to PostgreSQL?

Статья Панкаджа Капура (Pankaj Kapoor, Fujitsu) этакое обозрение уже не такой уж короткой (4 года) истории попыток интегрировать вертикальное хранение в PostgreSQL. Автор наблюдал этот процесс не как посторонний: Fujitsu, где он работает, предлагала сообществу свой Vertical Clustered Index в 2016, одновременно с патчем подобной направленности, предложенным Альваро Эррера (lvaro Herrera, 2ndQuadrant, теперь EDB). Со стороны Fujitsu внедрением Vertical Clustered Index занимался Харибабу Коми (Haribabu Komi). Но сообщество пошло другим путём: сосредоточило усилия на универсальном решении на API методов доступа к таблицам, по образцу методов доступа к индексам.

Сейчас, на конец 2019-го через слой методов доступа идёт интеграция с таблицами альтернативного типа хранения, zheap, например. Но пока только с доступом на базе кортежей, то есть до интеграции вертикального хранилища (реальный претендент Zedstore) ещё далеко.

Автор предлагает заодно ознакомиться со своей презентацией на PGCon2019.

Напомним и о vops интересном расширении Postgres Professional, поддерживающем векторные операции. Данные там группируются по значениям столбцов и хранятся в виде плиток (паркета).

Insert-Only Data Modelling To Smooth Peaks On Slow Disks

Каарел Моппел (Kaarel Moppel, Cybertec) предлагает неожиданный и даже контринтуитивный способ сглаживания пиков: вместо UPDATE данных только INSERT на время пиков нагрузки, чтобы потом, в спокойные часы разобраться с данными, вставленными в экстремальной ситуации. Выигрыш в скорости INSERT vs UPDATE на тестовых данных Каарела (100 млн записей) получился раза в 3. Конечно, этот способ подходит отнюдь не во всех случаях, но Каарел говорит об опыте конкретной проблемы заказчика, у которого не было возможности или желания апгрейдить железо из-за пиков, в то время, как в обычных условиях система справлялась.

10 Things I Hate About PostgreSQL

Под Новый Год лучше бы уж не о ненависти, а о любви. Ну да ладно. Рик Бронсон (Rick Branson), работавший в том числе с петабайтного масштаба проектами, решил подытожить 2020-й десяткой самых ненавистных ему особенностей PostgreSQL (некоторые наши спойлеры курсивом):

#1: Wraparound, чреватый катастрофой
[скорее всего когда-то в будущем XID-ы станут 64-разрядными целыми (то есть как уже давно в Postgres Pro Enterprise)];
#2: При переключении кластера (failover) могут потеряться данные;
#3: Неэффективная репликация, распространяющая испорченные данные;
#4: Частая сборка мусора в СУБД типа MVCC проходит болезненно
[Вся надежда Рика на будущий zheap];
#5: Принцип по процессу на соединение мешает масштабируемости
[Рик рассказывает, как использовал 2 слоя pgbouncer-ов и как доходило в общей сложности до миллиона процессов; а также скучает про тред-на-соединение в MySQL];
#6: Индекс по Primary Key очень прожорлив по части ресурсов
[Рик предлагает использовать индекс-таблицы];
#7: Для апгрейда мажорных версий может потребоваться остановка СУБД
[Из-за несовместимости бинарных форматов хранения файлов на диске могут потребоваться часы простоя. Это при потоковой репликации. Переход на логическую может решить проблему в будущем];
#8: Неуклюжая настройка репликации;
#9: Странная догма Никаких-подсказок-планировщику;
#10: Отсутствие компрессии на уровне блоков.

Но каждый из пунктов не так уж просто устроен: там масса оговорок и уточнений (учитывающих и реплики комментаторов). Ну а дальше автор поясняет, конечно, что никакой ненависти к PostgreSQL у него нет, просто нет идеальных СУБД, и бурно выражает уверенность в том, что великолепная команда разработчиков PostgreSQL все эти вопросы благополучно разрешит.

Waiting for PostgreSQL 14 Multirange datatypes

Как всегда активен Депеш, он же Хуберт Любашевски (Hubert Lubaczewski). Здесь он пишет о патче Александра Короткова. Как можно догадаться, многодиапазонные типы собираются из непересекающихся диапазонов. Как и диапазоны, они строятся на базе integer, bigintint, numeric, timestamp without time zone, timestamp with time zone, date.

Депеш создает многодиапазонные данные и пробует их на зуб: смотрит, какие индексы с ними уже можно создавать. btree уже точно можно, так что вот такой запрос будет ускоряться:

SELECT * FROM testWHERE ranges = '{[77.7909859996235,177.7909859996235],(1035.84122266822,1135.84122266822],(1000099.99954803,1000199.99954803]}';


How to install and configure PostgreSQL Debian/Ubuntu for developer use part 1

А здесь Депеш решил расписать шаги по установке PostgreSQL-13, настройке пользователей, редактировании pg_hba.conf и запуске PgAdmin под произвольным пользователем. Это азбука, но какие-то нюансы могут и пригодиться. Содержание следующих частей пока не анонсировано. На всякий случай напоминаем о существовании Малютки.

Waiting for PostgreSQL 14 pg_stat_statements: Track time at which all statistics were last reset.

Идёт постоянное усовершенствование pg_stat_statements. В 1-м и 3-м обзорах коммитфестов от Павла Лузанова уже было о некоторых коммитах. Депеш пишет о важном коммите Фуджи Масао (Fujii Masao): времени последнего ресета статистики. Информацию в pg_stat_statements время от времени очищают приложения и отдельные запросы:

SELECT pg_stat_statements_reset();


Теперь можно спросить у pg_stat_statements о времени последней чистки:

SELECT stats_reset FROM pg_stat_statements_info; dealloc |          stats_reset          ---------+-------------------------------       0 | 2020-12-20 12:06:02.099943+01

Postgres, PL/Python and SciPy/NumPy for Processing Images

Это продолжение статьи о сохранении картинок через Django-приложение в тип PostgreSQL bytea. На этот раз картинки ещё и обрабатывают фильтром.

Is Update The Same As Delete + Insert In PostgreSQL

Ответ: почти. И дальше Лоренц Альбе (Laurenz Albe) из Cybertec исследует это почти. Речь о блокировках при стандартном уровне изоляции: READ COMMITTED.
Session 1                     Session 2 BEGIN; UPDATE uptest SET id = 2   WHERE val = 42;                               SELECT id FROM uptest                                  WHERE val = 42                                  FOR UPDATE;  -- hangsCOMMIT;                               -- one row is returned

А в другой раз:
Session 1                     Session 2 BEGIN; DELETE FROM uptest   WHERE id = 1; INSERT INTO uptest VALUES (2, 42);                               SELECT id FROM uptest                                  WHERE val = 42                                  FOR UPDATE;  -- hangsCOMMIT;                               -- no row is returned

в первый раз возвращается 1 запись, во втором 0.
Дальше Лоренц исследует эту ситуацию, используя расширение pageinspect, да ещё и рассказывает о разнице поведения атрибутов infomask и infomask2 в этих двух случаях.

Конференции


Неопределённость сохраняется. Кто-то уже объявил о переформатировании в он-лайн.

PGCon 2021

В 2021-м пройдёт 28-го мая в сокращенном формате. От конференции осталась только Unconference, которая уместится в zoom. Записаться можно здесь.

Nordic PGDay 2021

Запланирована на 18 марта в Хельсинки. Об он-лайне пока ни слова. Год назад эта конференция была отменена из-за эпидемии.

Облака


Want more PostgreSQL? You just might like Babelfish

Этот проект откровенно ориентирован на тех, кто хочет беспроблемно мигрировать с MS SQL Server на PostgreSQL. Утверждается, что Bablefish это PostgreSQL, совместимый с SQL Server настолько, что приложения, под него написанные (в том числе с T-SQL и протоколом TDS), будут сразу работать.

Новости юриспруденции


Trademark Policy изменилась

Изменения касаются и Slonik-а то есть милой сердцам постгресистов картинки, и торговых марок.

Кто ты, бек-эндер?


Может ты бэкендер? Этот в высшей степени непростой вопрос разбирается в пространном исследовании Острые орфографические боли по всей длине слова и как от них избавиться на сайте ГЗОМ. Любители отгадывать зажмурьтесь: дальше ответы-спойлеры.

Сегодня нормативно:
Бэк-энд, бэк-энд-разработчик. В профессиональных текстах back-end-разработчик.

Соответствуют русской орфографии:
Бэкендер, бэк-эндовый.

Лет через семь могут возобладать:
Бэкенд, бэкендовый.



Предыдущие выпуски:
#26, #25, #24, #23, #22, #21, #20, #19, #18, #17, #16, #15, #14, #13, #12, #11 (спец), #10, #9, #8, #7, #6, #5, #4, #3, #2, #1
Подробнее..

Интеграция PHP проекта на GitHub и Scrutinizer

13.01.2021 04:12:47 | Автор: admin

Регистрируемся в Scrutinizer

Проще, наверное, войти через вашу учетную запись в GitHub, т.к. это избавит вас от необходимости линковать ваш GitHub профиль, а делать это все равно придется.

Для установки приложения Scrutinizer переходим по ссылке, этот шаг можно пропустить, но имейте ввиду, что в дальнейшем у вас не будут работать интерактивные плюшки и будет висеть нотификация: Scrutinizer GitHub App Is Not Installed...

Даем ему все скоупы, которые требует. Не бойтесь, Scrutinizer не удалит ваши репозитории и никак вам не навредит. Это нужно для того, чтобы приложение могло общаться с вашим GitHub по АПИ и в real-time управлять вашим Check Suite, давая ему обратную связь, и кодом в ваших PR для удобства ревью и тд.

Пример, как выглядит окно установки Scrutinizer

Создаем глобальную конфигурацию

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

Чтобы создать глобальную конфигурацию перейдите по ссылке.

Пример глобальной конфигурации для PHP проекта
build:    environment:        php: 7.3.15build_failure_conditions:  - 'project.metric_change("scrutinizer.quality", < -0.10)'  - 'elements.rating(<= D).exists'                                # No classes/methods with a rating of D or worse  - 'elements.rating(<= D).new.exists'                            # No new classes/methods with a rating of D or worse allowed  - 'issues.label("coding-style").exists'                         # No coding style issues allowed  - 'issues.label("coding-style").new.exists'                     # No new coding style issues allowed  - 'issues.severity(>= MAJOR).new.exists'                        # New issues of major or higher severity                          - 'project.metric("scrutinizer.quality", < 9)'                  # Code Quality Rating drops below 9  - 'patches.label("Doc Comments").exists'                        # No doc comments patches allowed  - 'patches.label("Spacing").exists'                             # No spacing patches allowedchecks:    php:        verify_property_names: true        verify_argument_usable_as_reference: true        verify_access_scope_valid: true        variable_existence: true        useless_calls: true        use_statement_alias_conflict: true        unused_variables: true        unused_properties: true        unused_parameters: true        unused_methods: true        unreachable_code: true        too_many_arguments: true        symfony_request_injection: true        switch_fallthrough_commented: true        sql_injection_vulnerabilities: true        simplify_boolean_return: true        security_vulnerabilities: true        return_in_constructor: true        return_doc_comments: true        return_doc_comment_if_not_inferrable: true        require_scope_for_methods: true        require_php_tag_first: true        remove_extra_empty_lines: true        property_assignments: true        properties_in_camelcaps: true        precedence_mistakes: true        precedence_in_conditions: true        phpunit_assertions: true        parse_doc_comments: true        parameters_in_camelcaps: true        parameter_non_unique: true        parameter_doc_comments: true        param_doc_comment_if_not_inferrable: true        overriding_private_members: true        overriding_parameter: true        non_commented_empty_catch_block: true        no_trait_type_hints: true        no_trailing_whitespace: true        no_short_variable_names:            minimum: '3'        no_short_open_tag: true        no_short_method_names:            minimum: '3'        no_property_on_interface: true        no_non_implemented_abstract_methods: true        no_long_variable_names:            maximum: '20'        no_goto: true        no_exit: true        no_eval: true        no_error_suppression: true        no_debug_code: true        naming_conventions:            local_variable: '^[a-z][a-zA-Z0-9]*$'            abstract_class_name: ^Abstract|Factory$            utility_class_name: 'Utils?$'            constant_name: '^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$'            property_name: '^[a-z][a-zA-Z0-9]*$'            method_name: '^(?:[a-z]|__)[a-zA-Z0-9]*$'            parameter_name: '^[a-z][a-zA-Z0-9]*$'            interface_name: '^[A-Z][a-zA-Z0-9]*Interface$'            type_name: '^[A-Z][a-zA-Z0-9]*$'            exception_name: '^[A-Z][a-zA-Z0-9]*Exception$'            isser_method_name: '^(?:is|has|should|may|supports)'        more_specific_types_in_doc_comments: true        missing_arguments: true        method_calls_on_non_object: true        instanceof_class_exists: true        foreach_usable_as_reference: true        foreach_traversable: true        fix_use_statements:            remove_unused: true            preserve_multiple: false            preserve_blanklines: false            order_alphabetically: false        fix_line_ending: true        fix_doc_comments: true        encourage_shallow_comparison: true        duplication: true        deprecated_code_usage: true        deadlock_detection_in_loops: true        comparison_always_same_result: true        code_rating: true        closure_use_not_conflicting: true        closure_use_modifiable: true        check_method_contracts:            verify_interface_like_constraints: true            verify_documented_constraints: true            verify_parent_constraints: true        catch_class_exists: true        call_to_parent_method: true        avoid_superglobals: true        avoid_length_functions_in_loops: true        avoid_entity_manager_injection: true        avoid_duplicate_types: true        avoid_closing_tag: true        assignment_of_null_return: true        argument_type_checks: true

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

Проверки для сборок
build_failure_conditions:  - 'project.metric_change("scrutinizer.quality", < -0.10)'  - 'elements.rating(<= D).exists'  - 'elements.rating(<= D).new.exists'   - 'issues.label("coding-style").exists'   - 'issues.label("coding-style").new.exists'                - 'issues.severity(>= MAJOR).new.exists'                                       - 'project.metric("scrutinizer.quality", < 9)'  - 'patches.label("Doc Comments").exists'  - 'patches.label("Spacing").exists' 

Хотел бы отметить, всегда указывайте ваше окружение (версию PHP, базы данных и тд), т.к. значения по умолчанию могут меняться и ваши сборки в один прекрасный день будут зафейлены. Что собственно и приключилось со мной буквально на днях, когда релизнулся PHP 8.0.1.

Настройка репозитория

По сути мы просто добавляем свой репозиторий с GitHub, для этого переходим по ссылке.

Пример окна добавления репозитория

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

Далее идем в настройки вашего репозитория, которые находятся вот тут:
https://scrutinizer-ci.com/g/ваш-логин/название-репозитория/settings

Настройка Check Suite

Тут немного остановимся и я расскажу почему.

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

За это время ваши обычные проверки в GitHub CI уже могут быть пройдены, линтеры показали ваши ошибки или вы вспомнили, что что-то забыли, и успеели толкнуть пару-тройку коммитов до завершения сборки Scrutinizer.

Tracking Settings

По умолчанию каждый коммит будет добавлять в очередь сборку. Таким образом, чтобы дождаться заветной зеленой галочки в CheckSuite, придется ждать не один час, ну а если там ошибка или ваши сборки очень сложные, то и того дольше.

  • Pull-Request Tracking - отвечает за запуск сборок только для Pull-реквестов в основную ветку.

  • Pull-Request Notification - отвечает за то, как вы хотите узнавать о результатах сборки и анализа, например, через GitHub Check Suite.

  • Tracked Branches - отвечает за запуск сборок при пушах. Рекомендую, выставить опцию "Track only branches listed below" и указать вашу основную ветку.

Здесь находится пример с правильными настройками

Auto-Cancel Non-Finished Inspections

Если вы все же успели толкнуть пару коммитов до завершения сборок, эти настройки отменят предыдущие задания и сразу перезапустят их для вашего последнего коммита.

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

Здесь находится пример с правильными настройками

Настройка конфигурации репозитория

Переходим по ссылке:
https://scrutinizer-ci.com/g/ваш-логин/название-репозитория/settings/build-config

Важно выбрать вашу глобальную конфигурацию.

Пример, как задействовать глобальную конфигурацию
Пример конфигурации для проекта для Postgres
build:    nodes:        coverage:            services:                postgres: 12            tests:                override:                    -                        command: |                            sed -e "s/\${USERNAME}/scrutinizer/" \                                -e "s/\${PASSWORD}/scrutinizer/" \                                -e "s/\${DATABASE}/scrutinizer/" \                                -e "s/\${HOST}/127.0.0.1/" \                                phpunit.xml.dist > phpunit.xml                            ./vendor/bin/phpunit \                                --verbose  \                                --stderr  \                                --coverage-clover build/logs/clover.xml \                                --coverage-text                        coverage:                            file: build/logs/clover.xml                            format: clover        analysis:            tests:                override:                    - php-scrutinizer-run                    -                        command: phpcs-run                        use_website_config: true    cache:        disabled: true        directories:            - vendor/filter:    excluded_paths:        - 'tests/*'

В некоторых случаях сборки могут падать из-за отсутствия phpcs в коде вашего репозитория, в таком случае добавьте этот файл.

phpcs.xml
<?xml version="1.0"?><ruleset>    <file>./</file>    <exclude-pattern>./vendor/*</exclude-pattern>    <exclude-pattern>./tests/*</exclude-pattern>    <exclude-pattern>./.github/*</exclude-pattern>    <rule ref="PSR1" /></ruleset>

А в ваш composer.json в секцию require-dev добавьте:

"squizlabs/php_codesniffer": "^3.5"

Начало работы

Теперь, давайте толкнем коммит в основную ветку и посмотрим, как выглядит Check Suite со Scrutinizer.

Пример корректной интеграции с GitHub

При желании эти проверки можно сделать обязательными (все или только часть) в настройках вашего репозитория на GitHub (в разделе настроек ограничений веток), - об этом я рассказывал в своем предыдущем посте про автоматизацию ручных действий с GitHub Actions.

Интерактив от Scrutinizer в ревью

После интеграции и успешно пройденной сборки в Scrutinizer появится три кнопки: Code Intelligence, Issues и Coverage.

По сути это визуализированный результат анализа вашего кода, очень помогает ревьюить, наверное...

А покрытие кода выглядит примерно так

При наведении на методы и переменные Code Intelligence подсвечивает типы возвращаемых значений, а зеленые маркеры справа от нумератора строк сообщают о покрытии тестами.

В целом, это удобно, хотя я к Code Intelligence еще не привык.

Итог

Я буду рад, если мой опыт был вам полезен и вот такие красивые отчеты вас будут мотивировать писать совершенный код.

Если у вас что-то не получилось с первого раза, не отчаивайтесь.

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

Ну а если, вы все же отчаялись и у вас ничего не получилось, мои контакты открыты для вас, напишите мне, и мы вместе решим вашу проблему.

Подробнее..

Расширяем возможности миграций Laravel за счет Postgres

15.01.2021 02:22:41 | Автор: admin

Все, кто однажды начинал вести более-менее нормальный Enterprise проект на Laravel, сталкивался с тем, что стандартных решений, которые предлагает Laravel из коробки, уже недостаточно.

А если вы, как и я, используете в своих проектах Postgres, то рано или поздно вам потребуются плюшки этой замечательной СУБД, такие как: различного рода индексы и констрейнты, расширения, новые типы и тд...

Сегодня, как вы уже заметили, мы будем говорить про Postgres, про миграции Laravel, как это все вместе подружить, в общем, обо всем том, чего нам не хватает в стандартных миграциях Лары.

Ну а для тех, кто не хочет погружаться в тонкости внутреннего устройства Laravel, может просто скачать пакет, расширяющий возможности миграций Laravel и Postgres по этой ссылке и использовать его в своих проектах.

Но я все же рекомендую не пролистывать, а прочитать все до конца.

Миграции

Вот как выглядит стандартная миграция в Laravel:

Пример обычной миграции
<?phpdeclare(strict_types=1);use Illuminate\Database\Migrations\Migration;use Illuminate\Database\Schema\Blueprint;use Illuminate\Support\Facades\Schema;class CreateDocuments extends Migration{    private const TABLE = 'documents';    public function up()    {        Schema::create(static::TABLE, function (Blueprint $table) {            $table->bigIncrements('id');            $table->timestamps();            $table->softDeletes();            $table->string('number');            $table->date('issued_date')->nullable();            $table->date('expiry_date')->nullable();            $table->string('file');            $table->bigInteger('author_id');            $table->bigInteger('type_id');            $table->foreign('author_id')->references('id')->on('users');            $table->foreign('type_id')->references('id')->on('document_types');        });    }    public function down()    {        Schema::dropIfExists(static::TABLE);    }}

Но, тут вы прочитали статью на хабре про новые типы в Postgres, например, tsrange и захотели добавить в миграцию что-то вроде этого...

$table->addColumn('tsrange', 'period')->nullable();

Казалось бы, все просто, но ваш перфекционизм наводит вас на мысль, а почему бы не залезть в сорцы и не пропатчить Laravel, ведь я буду часть использовать это, хочется чтобы можно было использовать это примерно так:

$table->tsRange('period')->nullable();

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

Пример как пропатчить Laravel миграции

Патчим Blueprint

<?phpBlueprint::macro('tsRange', function (string $columnName) {  return $this->addColumn('tsrange', $columnName);});

Патчим PostgresGrammar

<?phpPostgresGrammar::macro('typeTsrange', function () {  rerurn 'tsrange';});

Далее создаем какой-нить провайдер, типа ExtendDatabaseProvider:

<?phpuse Illuminate\Support\ServiceProvider;class DatabaseServiceProvider extends ServiceProvider{    public function register()    {        Blueprint::macro('tsRange', function (string $columnName) {            return $this->addColumn('tsrange', $columnName);        });        PostgresGrammar::macro('typeTsrange', function () {            return 'tsrange';        });    }}

Вроде бы все, запускаем миграцию, все работает..

И не важно, переопределили ли вы половину компонентов Laravel для работы с БД или воспользовались макросами и миксинами из MacroableTrait, круги ада еще не закончились.

Круги ада (часть 1)

И вот вы локально все это крутите, все работает как часы, написали +100500 строк кода, и решили выкатить готовую таску в гитлаб. Мы же идем в ногу со временем и там у нас Докер, CI, тесты и тд...

И вот мы замечаем, что наши миграции в "не локальном" окружении не работают из-за ошибки:

Doctrine\DBAL\Driver\PDOException: SQLSTATE[08006] [7]FATAL:  sorry, too many clients already

И вот ты сидишь и думаешь, что ты не так делаешь, начинаешь подпихивать в локальный .env окружения из CI вашего GitLab, переписывать код, вместо макросов переопределять разные классы, распихивать везде и всюду дебаги, все идеально, локально ошибки нет. А в пайплайнах CI не так-то просто дебажить, начинаешь пихать везде и всюду логирование, и это не помогает, ведь ошибка где-то внутри, в vendor. Но ты об этом еще пока не знаешь.

Затем, спустя целый дня гугления ошибки, решения так и нет, куча бессмысленных советов.

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

Важен контекст

Ошибка sorry, too many clients already может быть совершенно по любой причине.

Ты возвращаешься к началу, гуглишь то с чего начинал, с внедрения макросами в PostgresGrammar нового типа и вот чудо, ты натыкаешься на похожую проблему, но с первого взгляда она немного другая.... где кто-то, как и ты добавлял новый тип и у него не заводится БД. Но у него ошибка другая:

Doctrine\DBAL\DBALException: Unknown database type tsrange requested,Doctrine\DBAL\Platforms\PostgreSQL100Platform may not support it.

Отчаявшись, первая мысль, а чем черт не шутит... ты пробуешь чужие решения, даже самые абсурдные и в один прекрасный день все начинает работать. Вы уже догадались в чем дело?

Барабанная дробь

Any Doctrine type that you use has to be registered with \Doctrine\DBAL\Types\Type::addType().

You can get a list of all the known types with \Doctrine\DBAL\Types\Type::getTypesMap().

If this error occurs during database introspection then you might have forgotten to register all database types for a Doctrine Type.

Use AbstractPlatform#registerDoctrineTypeMapping() or have your custom types implement Type#getMappedDatabaseTypes().

If the type name is empty you might have a problem with the cache or forgot some mapping information.

Иными словами, нужно успеть зарегистрировать тип в Doctrine\Dbal прежде, чем до вашего Database Connection дойдет информация, что вы используете кастомные типы (под кастомными я подразумеваю те, которые есть в Postgres, но отсутствуют в заветном getTypesMap в недрах Doctrine.

Круги ада (часть 2)

Вы лезете в исходники, куда-то очень глубоко в vendor в недры doctrine\dbal...

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

О боже, часть из них приватные!

Все больше не могу, это единственные мысли и слова, которые выходят из ваших уст..

Руки опускаются окончательно..

Спасительный круг

Не буду ходить вокруг, да около.

Это, как вы уже поняли, был мой личный опыт, мои руки не опустились, все-таки я победил этот великий и ужасный Doctrine.

Подумаем о будущем

А что, если я не первый, что если не мне одному надо это, что если сделать публичный пакет, который бы позволял расширять возможности наших миграций любому, добавлять новые типы, чтобы это было просто, прозрачно, и чтобы не приходилось лезть в исходники Laravel и Doctrine, и чтобы он работал по принципу автоботов.

Помните, как Оптимус Прайм при помощи трейлера приобретал способности летать, а другие автоботы, были для него своего рода доп. орудиями.

Представим себе такой DatabaseProvider, который мы внедряем в свой проект вместо стандартного от Laravel, опишем структуру будущих Extension-ов в виде маленьких библиотек с похожей структурой, чтобы они легко коннектились к нашему провайдеру, и забыть, как страшный сон исходники Doctrine.

Основные компоненты

Эти объекты нам надо модифицировать, но сделать это в стиле ООП, сбоку, по типу как трейты иньектятся в классы:

  • Blueprint - объект, использующийся в миграциях, по сути билдер

  • Builder - он же фасад Schema

  • PostgresGrammar - объект для компиляции Blueprint-а в SQL-выражения

  • Types - наши типы

Давайте, придумаем объект, который будет подмешивать объекты расширений во внутренние объекты Laravel таким образом, чтобы и овцы были целы и волки сыты, имею ввиду, чтобы IDE был счастлив, все работало, а наш код был понятным.

Пример класса, описывающего такое расширение
<?phpnamespace Umbrellio\Postgres\Extensions;use Illuminate\Support\Traits\Macroable;use Umbrellio\Postgres\Extensions\Exceptions\MacroableMissedException;use Umbrellio\Postgres\Extensions\Exceptions\MixinInvalidException;abstract class AbstractExtension extends AbstractComponent{    abstract public static function getMixins(): array;    abstract public static function getName(): string;    public static function getTypes(): array    {        return [];    }    final public static function register(): void    {        collect(static::getMixins())->each(static function ($extension, $mixin) {            if (!is_subclass_of($mixin, AbstractComponent::class)) {                throw new MixinInvalidException(sprintf(                    'Mixed class %s is not descendant of %s.',                    $mixin,                    AbstractComponent::class                ));            }            if (!method_exists($extension, 'mixin')) {                throw new MacroableMissedException(sprintf('Class %s doesnt use Macroable Trait.', $extension));            }            /** @var Macroable $extension */            $extension::mixin(new $mixin());        });    }}

Теперь, пропатчим соединение базы данных, чтобы оно умело работать с этим объектом и решало все наши проблемы, регистрировало в нужные внутренние компоненты Laravel наши дополнения, в том числе и решало проблему с регистрацией типов в Doctrine.

Патчим PostgresConnection
<?phpnamespace Umbrellio\Postgres;use DateTimeInterface;use Doctrine\DBAL\Connection;use Doctrine\DBAL\Events;use Illuminate\Database\PostgresConnection as BasePostgresConnection;use Illuminate\Support\Traits\Macroable;use PDO;use Umbrellio\Postgres\Extensions\AbstractExtension;use Umbrellio\Postgres\Extensions\Exceptions\ExtensionInvalidException;use Umbrellio\Postgres\Schema\Builder;use Umbrellio\Postgres\Schema\Grammars\PostgresGrammar;use Umbrellio\Postgres\Schema\Subscribers\SchemaAlterTableChangeColumnSubscriber;class PostgresConnection extends BasePostgresConnection{    use Macroable;    private static $extensions = [];    final public static function registerExtension(string $extension): void    {        if (!is_subclass_of($extension, AbstractExtension::class)) {            throw new ExtensionInvalidException(sprintf(                'Class %s must be implemented from %s',                $extension,                AbstractExtension::class            ));        }        self::$extensions[$extension::getName()] = $extension;    }    public function getSchemaBuilder()    {        if ($this->schemaGrammar === null) {            $this->useDefaultSchemaGrammar();        }        return new Builder($this);    }    public function useDefaultPostProcessor(): void    {        parent::useDefaultPostProcessor();        $this->registerExtensions();    }    protected function getDefaultSchemaGrammar()    {        return $this->withTablePrefix(new PostgresGrammar());    }    private function registerExtensions(): void    {        collect(self::$extensions)->each(function ($extension) {            /** @var AbstractExtension $extension */            $extension::register();            foreach ($extension::getTypes() as $type => $typeClass) {                $this                    ->getSchemaBuilder()                    ->registerCustomDoctrineType($typeClass, $type, $type);            }        });    }}

А также необходимо переопределить провайдер и фабрику для работы с БД:

Патчим DatabaseProvider
<?phpnamespace Umbrellio\Postgres;use Illuminate\Database\DatabaseManager;use Illuminate\Database\DatabaseServiceProvider;use Umbrellio\Postgres\Connectors\ConnectionFactory;class UmbrellioPostgresProvider extends DatabaseServiceProvider{    protected function registerConnectionServices(): void    {        $this->app->singleton('db.factory', function ($app) {            return new ConnectionFactory($app);        });        $this->app->singleton('db', function ($app) {            return new DatabaseManager($app, $app['db.factory']);        });        $this->app->bind('db.connection', function ($app) {            return $app['db']->connection();        });    }}
Патчим ConnectionFactory
<?phpnamespace Umbrellio\Postgres\Connectors;use Illuminate\Database\Connection;use Illuminate\Database\Connectors\ConnectionFactory as ConnectionFactoryBase;use Umbrellio\Postgres\PostgresConnection;class ConnectionFactory extends ConnectionFactoryBase{    protected function createConnection($driver, $connection, $database, $prefix = '', array $config = [])    {        if ($resolver = Connection::getResolver($driver)) {            return $resolver($connection, $database, $prefix, $config);        }        if ($driver === 'pgsql') {            return new PostgresConnection($connection, $database, $prefix, $config);        }        return parent::createConnection($driver, $connection, $database, $prefix, $config);    }}

Начало работы

Представим что нам надо добавить поддержку нового типа tsrange в наши миграции. Как будет выглядеть наше расширение в нашем проекте теперь.

TsRangeExtension.php
<?phpnamespace App\Extensions\TsRange;use App\Extensions\TsRange\Schema\Grammars\TsRangeSchemaGrammar;use App\Extensions\TsRange\Schema\TsRangeBlueprint;use App\Extensions\TsRange\Types\TsRangeType;use Umbrellio\Postgres\Extensions\AbstractExtension;use Umbrellio\Postgres\Schema\Blueprint;use Umbrellio\Postgres\Schema\Grammars\PostgresGrammar;class TsRangeExtension extends AbstractExtension{    public const NAME = TsRangeType::TYPE_NAME;    public static function getMixins(): array    {        return [            TsRangeBlueprint::class => Blueprint::class,            TsRangeSchemaGrammar::class => PostgresGrammar::class,            // ... список миксинов может включать в себя почти любой внутренний компонент Laravel        ];    }    public static function getName(): string    {        return static::NAME;    }    public static function getTypes(): array    {        return [            static::NAME => TsRangeType::class,        ];    }}
TsRangeBlueprint.php
<?phpnamespace App\Extensions\TsRange\Schema;use Illuminate\Support\Fluent;use App\Extensions\TsRange\Types\TsRangeType;use Umbrellio\Postgres\Extensions\Schema\AbstractBlueprint;class TsRangeBlueprint extends AbstractBlueprint{    public function tsrange()    {        return function (string $column): Fluent {            return $this->addColumn(TsRangeType::TYPE_NAME, $column);        };    }}
TsRangeSchemaGrammar.php
<?phpnamespace App\Extensions\TsRange\Schema\Grammars;use App\Extensions\TsRange\Types\TsRangeType;use Umbrellio\Postgres\Extensions\Schema\Grammar\AbstractGrammar;class TsRangeSchemaGrammar extends AbstractGrammar{    protected function typeTsrange()    {        return function (): string {            return TsRangeType::TYPE_NAME;        };    }}
TsRangeType.php
<?phpnamespace App\Extensions\TsRange\Types;use Doctrine\DBAL\Platforms\AbstractPlatform;use Doctrine\DBAL\Types\Type;class TsRangeType extends Type{    public const TYPE_NAME = 'tsrange';        public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string    {        return static::TYPE_NAME;    }    public function convertToPHPValue($value, AbstractPlatform $platform): ?array    {        //...        return $value;      }    public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string    {        //...              return $value;    }    public function getName(): string    {        return self::TYPE_NAME;    }}

Теперь необходимо зарегистрировать наше расширение TsRangeExtension в нашем провайдере для работы с БД:

<?phpnamespace App\TsRange\Providers;use Illuminate\Support\ServiceProvider;use App\Extensions\TsRange\TsRangeExtension;use Umbrellio\Postgres\PostgresConnection;class TsRangeExtensionProvider extends ServiceProvider{    public function register(): void    {        PostgresConnection::registerExtension(TsRangeExtension::class);    }}

Итог

Вы можете писать свои расширения для Postgres имплементируя AbstractExtension, на мой взгляд, очень быстро и просто, не вникая в тонкости работы Laravel и Doctrine.

Это мой первый опыт, сделать что-то полезное для PHP сообщества, для тех кто использует в своих проектах Laravel / Postgres, не судите строго, пожалуйста.

Но я буду рад обратной связи, в любом ее проявлении, в Issues / Pull-реквестах, или в комментах относительно не только моей публикации, но и пакета в целом приму любую критику.

Пощупать данный пакет можно на GitHub: laravel-pg-extensions.

Спасибо за внимание.

Подробнее..
Категории: Postgresql , Open source , Laravel , Php , Github , Postgres

Postgresso 28

02.02.2021 04:10:20 | Автор: admin


Привет всем уже в 21-м году. Надеемся, он будет добрей к нам, чем прошлый. Жизнь продолжается. И мы продолжаем знакомить вас с самыми интересными новостями PostgreSQL. Для разнообразия начну с конференций: этот жанр больше всего пострадал.

Конференции


Организаторы конференций выбирают разные стратегии в условиях карантина. Самый простой отменить, но лучше чем-то компенсировать.

Nordic PGDay 2021

Отменена. Рассчитывают на Хельсинки в марте 2022. Виртуального варианта не будет, но собираются сфокусироваться на PostgreSQL-треке FOSDEM 2021 в феврале. На сайте написано 2022, но имеется в виду, судя по всему FOSDEM 2021, о котором ниже.

А вот подход Highload++. Бескомпромиссный никакого онлайна:
Highload++ 2020 (2021)

Конференцию HighLoad++ не стали переносить в онлайн решили, что она для этого слишком масштабная. Но даты передвинули с 9-10 ноября 2020 г. на 20-21 мая 2021 года. Должна пройти в Москве в Крокус Экспо 3.

А вот полная противоположность:
FOSDEM 2021

Никакого Брюсселя, в 2021 только онлайн. Не только бесплатно, но и регистрации даже не требуется. Среди участников этой огромной конференции немало докладчиков, известных среди российских постгресистов: Олег Бартунов, Павел Борисов, Алексей Кондратов, Анастасия Лубенникова, Никита Глухов (Postgres Professional), Николай Самохвалов (Postgres.ai), Пётр Зайцев (Percona), Андрей Бородин (Yandex), Олег Иванов (Samsung AI Center, он автор плагина AQO в Postgres Pro Enterprise).
Расписание можно попробовать изучить здесь. Поток PostgreSQL здесь.

PGConf.Online 2021

Последняя в этом списке, компенсирую большим количеством знаков: у меня просто больше информации.
Здесь комбинация оф и он: офлайн-конференция PGConf.Russia 2021 запланирована на на конец мая начало июня 2021 года. А 1-3 марта будет проведена онлайн-конференция с соответствующим названием PGConf.Online 2021.

Темы конференции:
  • Postgres на предприятии;
  • Масштабируемость;
  • Высокие нагрузки и очень большие базы данных;
  • devops;
  • Переход на Postgres.

Участие в онлайновой конференции бесплатное. Всем желающим участвовать нужно предварительно зарегистрироваться на сайте, трансляция докладов будет вестись из личных кабинетов. Если уже оплатили PGConf.Russia 2021, то регистрироваться повторно не нужно. Регистрация действительна для обоих событий PGConf.Online и ближайшего PGConf.Russia. Также можно отказаться от участия в PGConf.Russia и вернуть свои деньги. Для этого надо написать на info@pgconf.ru.

Доклады принимаются до 10 февраля в двух форматах: кратком (22 мин + вопросы) и полном (45 мин + вопросы) на русском и английском языках. Также приветствуются мастер-классы с практическими упражнениями и обучающие лекции по вопросам расширенной разработки и DBA. Мастер-классы могут длиться 90 или 180 минут.

На PGConf.Online 2021 возможны доклады как онлайн, так и предварительно записанные, по желанию. Планируется, что даже после записанного выступления докладчик будет онлайн отвечать на вопросы, которые будут собираться в чате модераторами.

Соревнования


PostgreSQL is the DBMS of the Year 2020

СУБД года! Это не рейтинг популярности, а рейтинг роста популярности. Из рейтингов на январь 2021 вычитаются рейтинги за январь 2020. А они вычисляются по методологии экспертов db-engines. По абсолютной, а не дифференциальной популярности postgreSQL по-прежнему на 4-м месте.
О соревновании x86 с ARM в облаках см. далее.

Облака


Тема ARM в облаках набирает обороты. Что не удивительно ARM наступает широким фронтом: суперкомпьютер на ARM взобрался на верхушку Top500; новые попытки Apple; процессор Whitechapel у Google; процессоры от Ampere Computing появятся в облаках Oracle; ну и, конечно, процессоры AWS Graviton2 с ядром Arm Neoverse в исполнении Amazon.

Вот две статьи: в одной Hosting Postgres on an AWS EC2 t4g Graviton2 ARM Instance рассказывается, как запустить и настроить инстансы t4g (но ещё и о выборе EC2 vs RDS); в другой PostgreSQL on ARM-based AWS EC2 Instances: Is It Any Good? исследуется производительность. Об этом чуть подробней: Жобин Аугустин (Jobin Augustine) и Сергей Кузьмичев (Sergey Kuzmichev) из Percona тестировали ARM vs. x86. ARM на инстансах m6gd.8xlarge на базе ARM-процессоров AWS Graviton2. Сам Amazon позиционирует их как обеспечивающий на 40 % лучшее соотношение цены и производительности по сравнению с показателями x86-инстансов M5 в тестах m5d.8xlarge. В обоих инстансах по 32 виртуальных процессора.

Для разминки прогнали на pgbench, ARM выиграл и на Read-Write и на Read-Only в районе 20%. При этом тестировщики не забывали отключать и включать проверку контрольных сумм мало ли что, архитектура разная. Затем перешли к основным перконовским тестам sysbench-tpcc. Размер базы подбирали так, чтобы она умещалась в память. Стали смотреть результаты на числе потоков от 16 до 128. Получилось, что на 16 примерно та же картина, как и на pgbench, а когда потоков больше, чем виртуальных процессоров, игра в ничью. Чтобы уж совсем не огорчать поклонников x86, авторы констатировали худшую производительность у ARM на тестах, оценивающих ввод-вывод. Но и то при 128 потоках. Подробности в статье и на гитхабе.

Теперь информация, связанных с апгрейдом в облаках Amazon:
Ensuring Consistent Performance After Version Upgrades with Amazon Aurora PostgreSQL Query Plan Management

Query Plan Management это расширение apg_plan_mgmt. В статье показано, как после апгрейда кластера Aurora PostgreSQL с 9.6.11 на 10.12 при помощи этого инструмента можно легко проверить, использует ли планировщик одобренный в предыдущей версии план запроса (планы могут получать статус Approved, Rejected, Unapproved, или Preferred).

Кстати, о версиях:
Amazon RDS for PostgreSQL Supports 12.5

RDS теперь поддерживает минорные версии: 12.5, 11.10, 10.15, 9.6.20 и 9.5.24.

Релизы


pgAdmin 4 v4.30

В этой версии появился (пока в статусе бета) новый инструмент: ERD диаграммы сущность-связь, то есть графическая репрезентация таблиц, столбцов и их взаимосвязей. Можно визуализировать уже существующие схемы БД, можно создавать мышью новые, а ERD сгенерит соответствующие SQL. Также появилась поддержка Kerberos.

PostgreSQL-плагин для Zabbix 5.2.4rc1

В новой версии появилась поддержка custom query для плагина PostgreSQL. Теперь можно создать файл .sql и положить его на свою машину. Далее в web-интерфейсе своего Zabbix-сервера в шаблоне для Zabbix-Agent2 находим элемент под названием pgsql.query.custom и в нем указываем макрос, который должен иметь значение имени sql файла с запросом (при этом в конфигурационном файле Zabbix-Agent2 нужно указать путь на машине к папке с sql файлом. И тогда агент сам выполняет запрос в sql файле и пришлет результат на Zabbix-сервер с остальными, дефолтными метриками. Автор плагина Дарья Вилкова, Postgres Professional.

Целая серия новых версий FDW:

sqlite_fdw 1.3.1
InfluxDB fdw 0.3
griddb_fdw 1.3

PostgresNIO 1.0

Это неблокирующий, event-driven клиент для Swift от Vapor, построенный на эппловской SwiftNIO. Этот клиент устанавливает соединение, авторизует и отправляет запрос на сервер, а результат обратно. Использует протокол PostgreSQL. Умеет создавать пул соединений. И ещё есть пакеты более высокого уровня поверх PostgresNIO postgres-kit.

PGMoon 12.0-1

pgmoon это клиентская библиотека, написанная на чистом Lua (MoonScript). pgmoon с самого начала была разработана для использования в OpenResty web-платформе на базе докрученного Nginx), чтобы можно было пользоваться API 100% неблокирующих cosockets для асинхронных запросов.

Ещё статьи


Расширение кластера PostgreSQL размером 5,7 ТБ и переход с версии 9.6 на 12.4

Статья в блоге Альфа-Банка, автор оригинала Томми Ли (Tommy Li, Coffee Meets Bagel приложение для романтических знакомств с системой курирования).

Базы работали на 6 серверах Postgres на инстансах i3.8xlarge в амазоновском облаке: одна главная нода, три реплики для раздачи веб-трафика только для чтения, балансируемые с помощью HAProxy, один сервер для асинхронных воркеров и один сервер для ETL (Extract, Transform, Load) и Business Intelligence. Для поддержания реплик в актуальном состоянии использовалась потоковая репликация.

Надо было одновременно проапгрейдить Postgres и перейти с i3.8xlarge на i3.16xlarge при минимальной суммарной остановке 4 ч. (а вышло полчаса). Для миграции использовали pglogical. Также в статье из этого опыта извлекли уроки. Эта статья вызвала справедливые и несправедливые замечания в комментариях. Так что примечателен не только сам случай, но и реакция на него, да и тот факт, что перевод статьи появился не где-нибудь, а на хабр-блоге Альфа-Банка (до этого там о базах данных ничего, кажется, не было).

PostgreSQL Scaling Advice For 2021

Каарел Моппел (Kaarel Moppel, Cybertec), чьи статьи регулярно попадают в наши обзоры, дерзнул дать советы тем, кто озабочен будущим масштабированием своих систем. Каарел признаётся, что воодушевился роликом Distributed MySQL Architectures Past, Present, Future Петра Зайцева, основателя и гендира Percona, и приложил (так как, по его, Каарела, словам, MySQL и Postgres суть сводные братья) некоторые выводы Петра к родной PostgreSQL и добавил собственные.

Итого: что даёт обычный Postgres?
  • один инстанс PostgreSQL легко выполняет сотни тысяч транзакций в секунду;
  • одна нода обычно выполняет десятки тысяч пишущих транзакций в секунду;
  • один инстанс Postgres легко справляется с десятками ТБ данных;
  • один инстанс на одной ноде даёт буквально пуленепробиваемую надёжность при должной заботе о согласованности данных;
  • в причинах сбоев легко разобраться, поэтому данные можно восстановить.


О чём не стоит забывать, когда озаботился масштабированием?
  • не бойтесь заводить свои собственные (а не поддерживаемые в облаке) базы данных;
  • старайтесь избегать архитектуры данных, у которой в основе одна большая таблица;
  • убедитесь, что вы выбрали подходящий ключ разбиения при шардинге вашей таблицы/базы.


Агрегаты в БД

Кирилл Боровиков aka Kilor (компания Тензор) на этот раз обратился к агрегатам. Это мини-серия из двух статей: Агрегаты в БД зачем, как, а стоит ли? и продолжение Агрегаты в БД эффективная обработка потока фактов. В первой движение мысли от count(*) к подсчетам с парсингом EXPLAIN, к сбору агрегатов в отдельную таблицу, к хранению временных агрегатов в памяти процесса и даже к хранению их вообще в другой СУБД.

Во второй статье агрегация обретает бизнес-очертания: пересчет остатков и ведение сводных продаж по товарам при их постоянных отгрузках, или агрегация сальдо и оборотов по бухгалтерским счетам, при массовых изменениях проводок. Цель: агрегаты по продажам в разрезе товар/день/кол-во. Разных товаров очень много и отгрузок много. Решение: конкурентная обработка очередей, чтение из курсора читайте подробности.

Образование


Чёрная Малютка

Вышла новая версия знаменитой книжки-малышки
Postgres: первое знакомство.



Книжечка проапгрейдилась до версии PostgreSQL 13. В бумажном виде она, как и раньше, будет раздаваться на конференциях, которые проходят с участием Postgres Professional. PDF можно скачать.

DEV2: Разработка серверной части приложений PostgreSQL 12. Расширенный курс.

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

Митапы и подкасты


Постгрес-вторник с Петром Зайцевым

Петра Зайцева, основателя Percona, Николай Самохвалов и Илья Космодемьянский зазывали на свои Вторники целый год. Свершилось. Был разговор о компании (из которого выяснилось, что сейчас в компании около 300 сотрудников, из них человек 50 постгресистов); о причинах дрейфа компании от MySQL и MongoDB в сторону PostgreSQL (не по любви, и не из-за технологических причин, а просто в это сторону двигались клиенты и потенциальные клиенты); о разной атмосфере в комьюнити MySQL, MongoBD и PostgreSQL (второе самое монополистическое, а третье самое открытое). Но гвоздь программы перконовская утилита мониторинга pg_stat_monitor.

Монитор опирается на расширении pg_stat_statements, но добавляет некоторую функциональность. Можно, например, посмотреть тексты запросов, отбирающих много ресурсов, сравнить прожорливость одного и того же запроса с разными планами; монитор знает название приложения, отправившего запрос. В этом контексте возник и разговор о новом расширении PWR (pgpro_pwr), вошедшем в Postgres Pro Standard и Enterprise 13. Это, кажется, обсудят на следующем Вторнике (мы же обещали статью о нём и обещание скоро сдержим).
Подробнее..

SQL миграции в Postgres. Часть 1

03.02.2021 00:17:16 | Автор: admin

Как обновить значение атрибута для всех записей таблицы? Как добавить первичный или уникальный ключ в таблицу? Как разбить таблицу на две? Как ...

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

На эти и другие вопросы, возникающие при проведении миграций схемы и данных в PostgreSQL, постараемся дать ответы в виде практических советов.

Эта статья расшифровка выступления на конференции SmartDataConf (здесь можно найти презентацию, со временем появится видео). Текста получилось много, поэтому материал будет разбит на 2 статьи:

  • базовые миграции
  • подходы по обновлению больших таблиц.

В конце есть выжимка всей статьи в виде сводной таблицы-шпаргалки.

Содержание


Суть проблемы
Добавление столбца
Добавление столбца со значением по умолчанию
Удаление столбца
Создание индекса
Создание индекса для партиционированной таблицы
Создание ограничения NOT NULL
Создание внешнего ключа
Создание ограничения уникальности
Создание первичного ключа
Краткая шпаргалка с миграциями

Суть проблемы


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


При такой схеме обновления приложения зачастую происходят с простоем (downtime). В это же время можно обновлять БД. В такой ситуации главный критерий это время, то есть нужно выполнить миграцию как можно быстрее, чтобы минимизировать время недоступности сервиса.

Если приложение растет и появляется необходимость проводить релизы без простоя, мы начинаем использовать несколько серверов приложений. Их может быть сколько угодно, и они будут на разных версиях. В этом случае появляется необходимость обеспечения обратной совместимости.


На следующем этапе роста данные перестают влезать в одну БД. Мы начинаем масштабировать также и БД путем шардирования. Поскольку на практике синхронно проводить миграции нескольких баз данных очень сложно, это значит, что в какой-то момент они будут иметь разные схемы данных. Соответственно, мы будем работать в гетерогенной среде, где сервера приложений могут иметь разный код, а базы данных разные схемы данных.


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

Наша цель проводить SQL-миграции с минимальным влиянием на работу приложения, т.е. изменять данные или схему данных таким образом, чтобы приложение продолжало работать и пользователи ничего не замечали.

Добавление столбца


ALTER TABLE my_table ADD COLUMN new_column INTEGER -- быстро и безопасно

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

Предположим, у нас есть большая таблица, и мы делаем из нее SELECT всех данных. В зависимости от размера БД и самой таблицы он может длиться несколько секунд или даже минут.


На время выполнения транзакции захватывается самая слабая блокировка AccessShare, которая защищает от изменений структуры таблицы.

В этот момент приходит другая транзакция, которая как раз таки пытается сделать запрос ALTER TABLE к этой таблице. Команда ALTER TABLE, как уже было сказано ранее, захватывает блокировку AccessExclusive, которая не совместима вообще ни с какой другой. Она встает в очередь.

Эта очередь блокировок разгребается в строгом порядке, т.е. даже если после ALTER TABLE приходят другие запросы (например, также SELECTы), которые сами по себе не конфликтуют с первым запросом, они все встают в очередь за ALTER TABLE. В итоге приложение встало и ждет, пока ALTER TABLE выполнится.

Что делать в такой ситуации? Можно ограничить время захвата блокировки с помощью команды SET lock_timeout. Выполняем эту команду перед ALTER TABLE (ключевое слово LOCAL означает, что настройка действует только в пределах текущей транзакции, иначе в пределах текущей сессии):

SET LOCAL lock_timeout TO '100ms'

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

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

Добавление столбца со значением по умолчанию


-- быстро и безопасно с PG 11ALTER TABLE my_table ADD COLUMN new_column INTEGER DEFAULT 42

Если эта команда выполняется в PostgreSQL старой версии (ниже 11), то это приводит к перезаписи всех строк в таблице. Очевидно, что если таблица большая, то это может занять много времени. А поскольку на время выполнения захватывается строгая блокировка (AccessExclusive), то все запросы к таблице также блокируются.

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

Более того, с 11й версии также можно сразу создавать новый столбец и помечать его как NOT NULL:

-- быстро и безопасно с PG 11ALTER TABLE my_table ADD COLUMN new_column INTEGER DEFAULT 42 NOT NULL

Как быть, если PostgreSQL старше, чем 11?

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

ALTER TABLE my_table ADD COLUMN new_column INTEGER;ALTER TABLE my_table ALTER COLUMN new_column SET DEFAULT 42;

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

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

UPDATE my_table set new_column = 42 -- небезопасно на большой таблице

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

Удаление столбца


ALTER TABLE my_table DROP COLUMN new_column -- быстро и безопасно

Здесь логика такая же, как и при добавлении столбца: данные таблицы не модифицируются, происходит только изменение метаинформации. В данном случае столбец помечается как удаленный и недоступный при запросах. Это объясняет тот факт, что при удалении столбца в PostgreSQL физически место не освобождается (если не выполнять VACUUM FULL), то есть данные старых записей по-прежнему остаются в таблице, но недоступны при обращении. Освобождение происходит постепенно при перезаписи строк в таблице.

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

  • Для начала необходимо убрать все ограничения (NOT NULL, CHECK, ...), которые есть на этом столбце:
    ALTER TABLE my_table ALTER COLUMN new_column DROP NOT NULL
    
  • Следующий шаг обеспечить совместимость бэкенда. Нужно убедиться, что столбец нигде не используется. Например, в Hibernate необходимо пометить поле с помощью аннотации @Transient. В JOOQ, который мы используем, поле добавляется в исключения с помощью тэга <excludes>:
    <excludes>my_table.new_column</excludes>
    

    Также нужно внимательно посмотреть на запросы "SELECT *" фреймворки могут мапить все столбцы в структуру в коде (и наоборот) и, соответственно, снова можно столкнуться с проблемой обращения к несуществующему столбцу.

После вывода изменений на все сервера приложений можно удалить столбец.

Создание индекса


CREATE INDEX my_table_index ON my_table (name) -- небезопасно, блокировка таблицы

Те, кто работает с PostgreSQL, наверное, знают, что такая команда блокирует всю таблицу. Но еще с очень старой версии 8.2 существует ключевое слово CONCURRENTLY, которое позволяет создавать индекс в неблокирующем режиме.

CREATE CONCURRENTLY INDEX my_table_index ON my_table (name) -- безопасно

Команда работает медленнее, но не мешает параллельным запросам.

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

SELECT pg_index.indisvalid    FROM pg_class, pg_indexWHERE pg_index.indexrelid = pg_class.oid    AND pg_class.relname = 'my_table_index'

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

DROP INDEX CONCURRENTLY my_table_indexUPDATE my_table ...CREATE CONCURRENTLY INDEX my_table_index ON my_table (name)

Важно заметить, что команда REINDEX, которая как раз предназначена для пересоздания индекса, до 12й версии работает только в блокирующем режиме, что не дает возможности ее использовать. В 12й версии PostgreSQL появилась поддержка CONCURRENTLY, и теперь и ей можно пользоваться.

REINDEX INDEX CONCURRENTLY my_table_index -- с PG 12

Создание индекса для партиционированной таблицы


Отдельно стоит обсудить создание индексов для партиционированных таблиц. В PostgreSQL существует 2 вида партиционирования: через наследование и декларативное, появившееся в 10й версии. Рассмотрим оба на простом примере.

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

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

Родительская таблица:

CREATE TABLE my_table (...reg_date  date not null)

Дочерние партиции для 2020 и 2021 годов:

CREATE TABLE my_table_y2020 (CHECK ( reg_date >= DATE '2020-01-01' AND reg_date < DATE '2021-01-01' ))INHERITS (my_table);CREATE TABLE my_table_y2021 (CHECK ( reg_date >= DATE '2021-01-01' AND reg_date < DATE '2022-01-01' ))INHERITS (my_table);

Индексы по полю партиционирования для каждой из партиций:

CREATE INDEX ON my_table_y2020 (reg_date);CREATE INDEX ON my_table_y2021 (reg_date);

Создание триггера/правила для вставки данных в таблицу оставим за рамками.

Самое важное здесь то, что каждая из партиций это практически самостоятельная таблица, которая обслуживается по отдельности. Таким образом, создание новых индексов также проводится как с обычными таблицами:

CREATE CONCURRENTLY INDEX my_table_y2020_index ON my_table_y2020 (name);CREATE CONCURRENTLY INDEX my_table_y2021_index ON my_table_y2021 (name);

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

CREATE TABLE my_table (...) PARTITION BY RANGE (reg_date);CREATE TABLE my_table_y2020 PARTITION OF my_table FOR VALUES FROM ('2020-01-01') TO ('2020-12-31');CREATE TABLE my_table_y2021 PARTITION OF my_table FOR VALUES FROM ('2021-01-01') TO ('2021-12-31');

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

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

-- с PG 11 удобно для новой (пустой) партиционированной таблицыCREATE INDEX ON my_table (reg_date)

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

CREATE INDEX ON my_table (name) -- блокировка таблиц

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

  1. Создать индекс для родительской таблицы с опцией ONLY
    CREATE INDEX my_table_index ON ONLY my_table (name)
    

    Команда создаст пустой невалидный индекс без создания индексов для партиций.
  2. Создать индексы для каждой из партиций:
    CREATE CONCURRENTLY INDEX my_table_y2020_index ON my_table_y2020 (name);CREATE CONCURRENTLY INDEX my_table_y2021_index ON my_table_y2021 (name);
    
  3. Прикрепить индексы партиций к индексу родительской таблицы:
    ALTER INDEX my_table_index ATTACH PARTITION my_table_y2020_index;ALTER INDEX my_table_index ATTACH PARTITION my_table_y2021_index;
    
    Как только все индексы будут прикреплены, индекс родительской таблицы автоматически станет валидным.

Ограничения


Теперь пройдемся по ограничениям: NOT NULL, внешние, уникальные и первичные ключи.

Создание ограничения NOT NULL


ALTER TABLE my_table ALTER COLUMN name SET NOT NULL -- блокировка таблицы

Создание ограничения таким образом приведет к сканированию всей таблицы все строки будут проверены на условие not null, и если таблица большая, то это может занять длительное время. Строгая блокировка, захватываемая этой командой, заблокирует все параллельные запросы до ее завершения.

Что можно сделать? В PostgreSQL есть другой тип ограничения, CHECK, с помощью которого можно получить желаемый результат. Это ограничение проверяет любое булево условие, состоящее из столбцов строки. В нашем случае условие тривиально CHECK (name IS NOT NULL). Но самое важное то, что ограничение CHECK поддерживает невалидность (ключевое слово NOT VALID):

ALTER TABLE my_table ADD CONSTRAINT chk_name_not_null     CHECK (name IS NOT NULL) NOT VALID -- безопасно, с PG 9.2

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

Для обеспечения гарантии, что существующие записи также удовлетворяют ограничению необходимо провести его валидацию (конечно же, предварительно обновив данные в таблице):

ALTER TABLE my_table VALIDATE CONSTRAINT chk_name_not_null

Команда итерируется по строкам таблицы и проверяет, что все записи не not null. Но в отличие от обычного NOT NULL ограничения, блокировка, захватываемая в этой команде, не такая строгая (ShareUpdateExclusive) она не блокирует операции insert, update и delete.

Создание внешнего ключа


ALTER TABLE my_table ADD CONSTRAINT fk_group     FOREIGN KEY (group_id) REFERENCES groups(id) -- блокировка обеих таблиц

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

К счастью, внешние ключи в PostgreSQL также поддерживают NOT VALID, а это значит мы можем использовать тот же подход, что был рассмотрен ранее с CHECK. Создаем невалидный внешний ключ:

ALTER TABLE my_table ADD CONSTRAINT fk_group     FOREIGN KEY (group_id)REFERENCES groups(id) NOT VALID

затем обновляем данные и проводим валидацию:

ALTER TABLE my_table VALIDATE CONSTRAINT fk_group_id


Создание ограничения уникальности


ALTER TABLE my_table ADD CONSTRAINT uk_my_table UNIQUE (id) -- блокировка таблицы

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

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

SELECT conindid index_oid, conindid::regclass index_name     FROM pg_constraint WHERE conname = 'uk_my_table_id'

При этом большая часть времени создания ограничения как раз таки уходит на индекс, а его последующая привязка к ограничению происходит очень быстро. Более того, если у вас уже есть созданный уникальный индекс, то такую привязку можно осуществить самостоятельно, создавая индекс с помощью ключевых слов USING INDEX:

ALTER TABLE my_table ADD CONSTRAINT uk_my_table_id UNIQUE     USING INDEX uk_my_table_id -- быстро, с PG 9.1

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

В этот момент может возникнуть вопрос зачем вообще создавать ограничение, если индекс выполняет ровно то, что требуется гарантирует уникальность значений? Если исключить из сравнения partial индексы, то с функциональной точки зрения результат действительно почти идентичен. Единственное отличие, которое удалось найти, состоит в том, что ограничения могут быть отложенными (deferrable), а индексы нет. В документации к старым версиям PostgreSQL (до 9.4 включительно) была сноска с информацией о том, что предпочтительный способ создания ограничения уникальности это явное создание ограничения ALTER TABLE ... ADD CONSTRAINT, а использование индексов стоит рассматривать как деталь реализации. Однако, в более свежих версиях эту сноску удалили.

Создание первичного ключа


Первичный ключ помимо уникальности накладывает ограничение not null. Если столбец изначально имел такое ограничение, то превратить его в первичный ключ не составит труда также создаем уникальный индекс CONCURRENTLY, а затем первичный ключ:

ALTER TABLE my_table ADD CONSTRAINT uk_my_table_id PRIMARY KEY     USING INDEX uk_my_table_id -- если id is NOT NULL

Важно отметить, что столбец должен иметь честное ограничение NOT NULL рассмотренный ранее подход с помощью CHECK не сработает.

Если же ограничения нет, то до 11-й версии PostgreSQL ничего не поделать без блокировки первичный ключ никак не создать.

Если у вас 11-й PostgreSQL или свежее, эту задачу можно решить путем создания нового столбца, который будет заменять существующий. Итак, по шагам.

Создаем новый столбец, который по умолчанию not null и имеет значение по умолчанию:

ALTER TABLE my_table ADD COLUMN new_id INTEGER NOT NULL DEFAULT -1 -- безопасно с PG 11

Настраиваем синхронизацию данных старого и нового столбцов с помощью триггера:

CREATE FUNCTION on_insert_or_update() RETURNS TRIGGER AS$$BEGIN  NEW.new_id = NEW.id;  RETURN NEW;END;$$ LANGUAGE plpgsql;CREATE TRIGGER trg BEFORE INSERT OR UPDATE ON my_tableFOR EACH ROW EXECUTE PROCEDURE on_insert_or_update();

Далее необходимо обновить данные строк, которые не затронулись триггером:

UPDATE my_table SET new_id = id WHERE new_id = -1 -- не делать на большой таблице

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

ALTER TABLE my_table RENAME COLUMN id TO old_id;ALTER TABLE my_table RENAME COLUMN new_id TO id;ALTER TABLE my_table RENAME COLUMN old_id TO new_id;

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

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

Краткая шпаргалка с миграциями


Перед любой командой, которая захватывает строгую блокировку (почти все ALTER TABLE ...) рекомендуется вызывать:

SET LOCAL lock_timeout TO '100ms'

Миграция Рекомендуемый подход
Добавление столбца
ALTER TABLE my_table ADD COLUMN new_column INTEGER
Добавление столбца со значением по умолчанию [и NOT NULL] c PostgreSQL 11:
ALTER TABLE my_table ADD COLUMN new_column INTEGER DEFAULT 42 [NOT NULL]

до PostgreSQL 11:
  1. ALTER TABLE my_table ADD COLUMN new_column INTEGER;ALTER TABLE my_table ALTER COLUMN new_column SET DEFAULT 42;
    
  2. обновление таблицы
Удаление столбца
  1. удаление ограничений (NOT NULL, CHECK и т.д.)
  2. подготовка кода
  3. ALTER TABLE my_table DROP COLUMN removed_column
    
Создание индекса
CREATE CONCURRENTLY INDEX my_table_index ON my_table (name)

Если завершилось ошибкой:
  1. DROP INDEX CONCURRENTLY my_table_index
    
  2. обновление таблицы
  3. CREATE CONCURRENTLY INDEX my_table_index ON my_table (name)
    

Создание индекса для партиционированной таблицы Партиционирование через наследование + декларативное в PG 10:
CREATE CONCURRENTLY INDEX my_table_y2020_index ON my_table_y2020 (name);CREATE CONCURRENTLY INDEX my_table_y2021_index ON my_table_y2021 (name);...

Декларативное партиционирование с PG 11:
  1. CREATE INDEX my_table_index ON ONLY my_table (name)
    
  2. CREATE CONCURRENTLY INDEX my_table_y2020_index ON my_table_y2020 (name);CREATE CONCURRENTLY INDEX my_table_y2021_index ON my_table_y2021 (name);...
    
  3. ALTER INDEX my_table_index ATTACH PARTITION my_table_y2020_index;ALTER INDEX my_table_index ATTACH PARTITION my_table_y2021_index;...
    
Создание ограничения NOT NULL
  1. ALTER TABLE my_table ADD CONSTRAINT chk_name_not_null CHECK (name IS NOT NULL) NOT VALID
    
  2. обновление таблицы
  3. ALTER TABLE my_table VALIDATE CONSTRAINT chk_name_not_null
    

Создание внешнего ключа
  1. ALTER TABLE my_table ADD CONSTRAINT fk_group FOREIGN KEY (group_id) REFERENCES groups(id) NOT VALID
    
  2. обновление таблицы
  3. ALTER TABLE my_table VALIDATE CONSTRAINT fk_group_id
    
Создание ограничения уникальности
  1. CREATE UNIQUE INDEX CONCURRENTLY uk_my_table_id ON my_table(id)
    
  2. ALTER TABLE my_table ADD CONSTRAINT uk_my_table_id UNIQUE USING INDEX uk_my_table_id
    
Создание первичного ключа Если столбец IS NOT NULL:
  1. CREATE UNIQUE INDEX CONCURRENTLY uk_my_table_id ON my_table(id)
    
  2. ALTER TABLE my_table ADD CONSTRAINT uk_my_table_id PRIMARY KEY USING INDEX uk_my_table_id
    

Если столбец IS NULL c PG 11:
  1. ALTER TABLE my_table ADD COLUMN new_id INTEGER NOT NULL DEFAULT -1
    
  2. CREATE FUNCTION on_insert_or_update() RETURNS TRIGGER AS$$BEGINNEW.new_id = NEW.id;RETURN NEW;END;$$ LANGUAGE plpgsql;CREATE TRIGGER trg BEFORE INSERT OR UPDATE ON my_tableFOR EACH ROW EXECUTE PROCEDURE on_insert_or_update();
    
  3. обновление таблицы
  4. ALTER TABLE my_table RENAME COLUMN id TO old_id;ALTER TABLE my_table RENAME COLUMN new_id TO id;ALTER TABLE my_table RENAME COLUMN old_id TO new_id;
    
  5. CREATE UNIQUE INDEX CONCURRENTLY uk_my_table_id ON my_table(id)
    
  6. ALTER TABLE my_table ADD CONSTRAINT uk_my_table_id PRIMARY KEY USING INDEX uk_my_table_id
    
  7. DROP TRIGGER trg ON my_table;DROP FUNCTION on_insert_or_update();ALTER TABLE my_table DROP COLUMN new_id;
    

В следующей статье рассмотрим подходы по обновлению больших таблиц.
Всем легких миграций!
Подробнее..

Постгрессо 29

28.02.2021 18:05:07 | Автор: admin

Мы продолжаем знакомить вас с самыми интересными новостями PostgreSQL.

Конференция PGConf.Online 2021


Она начинается уже 1-го марта и закончится 3-го. О ней подробно написано в статье Ивана Панченко, зам. гендира Postgres Professional.

На этой конференции (которая не вместо, а кроме офлайновой, теплой-ламповой, она ожидается в конце весны) будет рекордное число иностранных гостей чему явно поспособствовал онлайн-формат. В том числе на этот раз поучаствует и Саймон Риггс (Simon Riggs). Доклады в 3 потока с 10 утра до 6 вечера. А также мастер-классы.

Статьи


PostgreSQL 14: Часть 4 или январское наступление (Коммитфест 2021-01)

Очередной must read Павла Лузанова. Крупные изменения после первых трех относительно скромных коммитфестов (июльский, сентябрьский, ноябрьский).

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

  • Могут ли диапазоны содержать пропуски значений?
  • Зачем нужна индексная нотация типу json?
  • Может ли индекс при частых обновлениях разрастаться меньше, чем таблица? А вообще не разрастаться?
  • Сколько времени простаивали сеансы в idle_in_transaction?
  • Как построить ER-диаграмму для таблиц системного каталога?


Deep PostgreSQL Thoughts: The Linux Assassin

Слово deep уже пугает: не про ИИ ли это. Но нет. Джо Конвей (Joe Conway, Crunchy Data) действительно копает вглубь. Даже не Постгреса, не своего же расширения plr. На этот раз тема Жуткий Убийца, являющийся из недр Linux OOM Killer.

Джо начинает с истории: первые дискуссии в Postgres-сообществе и первые патчи в 2003-м году как заставить киллера работать по понятиям Postgres. Далее Джо поясняет отношения киллера и Postgres на уровне хоста (oom_score и oom_score_adj) и на уровне CGroup, поясняет, почему так важно не допустить прихода киллера.

И дальше Джо Конвей переходит к специфическим проблемам OOM Killer в Kubernetes это, видимо, и был главный повод для написания этой статьи. Оказывается, что там, в K8s, разрушительная деятельность киллера может начаться даже при относительно благополучном состоянии памяти. В K8s своп по умолчанию выключен. До этого момента автор не трогал тему свопа, которая, вообще-то, очень даже обсуждается среди постгресистов-практиков.

Джо ссылается на обстоятельную статью Криса Дауна (Chris Down) In defence of swap: common misconceptions, причём есть и русский перевод (не автопереводчиком): В защиту свопа: распространенные заблуждения. О Postgres там нет речи, но может заинтересовать и постгресистов.

Также ссылается он на статью The weird interactions of cgroups and linux page cache in hypervisor environments в блоге компании StorPool, где в команде в основном болгарские фамилии.

Далее Джо Конвей плавно переходит к разработкам и усилиям Crunchy Data в треугольнике PostgreSQL Kubernetes ядро Linux.

??
Акула жуёт гугловый кабель (The Guardian??)

Things I Wished More Developers Knew About Databases

Статья не (только) о Postgres. Иногда полезно ещё разок глянуть на разные СУБД с птичьего полёта. Вот внушительный список тем, о которых стоит помнить разработчикам приложений. В статье Джоанна Доган (Jaana Dogan) не поленилась их разворачивать и развивать. Иногда в неожиданную сторону: в пункте #1 мы, например, узнаём, что гугловские кабели давеча покусали акулы. Немало SQL-примеров, схем и есть матрица PostgreSQL vs. MySQL.

  • Если сеть доступна 99.999% времени, вам сильно повезло;
  • ACID понимают по-разному;
  • у каждой СУБД свои возможности поддержки согласованности и изоляции;
  • оптимистические блокировки могут помочь, когда удерживать эксклюзивные блокировки нет возможности;
  • есть аномалии кроме грязного чтения и потери данных;
  • моя СУБД, в каком порядке хочу исполнять транзакции, в таком и исполняю;
  • шардинг на уровне приложения не означает шардинг вне СУБД;
  • AUTOINCREMENT может преподнести неприятные сюрпризы;
  • устаревшие данные могут быть полезны и помогают обойтись без блокировок;
  • рассогласования из-за часов;
  • под задержками (latency) могут подразумевать разное;
  • надо оценивать производительность не по усредненным показателям, а по критическим операциям/транзакциям;
  • вложенные транзакции небезопасны;
  • транзакции не должны поддерживать состояния приложений;
  • планировщик поможет узнать многое о базе данных;
  • миграции без останова сложны, но возможны;
  • существенный рост базы данных увеличивает непредсказуемость.


Troubleshooting Performance Issues Due to Disk and RAM

Хамид Ахтар (Hamid Akhtar, HighGo, Китай) написал простенькую, но небесполезную памятку для тех, кто хочет быстро сузить круг подозреваемых при поиске проблем с железом. Начав с совсем очевидных top, free и df, он обращается к утилитам анализа производительности дисков, процессора и памяти, и предлагает полезные наборы их опций:
iostat (информация и о диске, и о процессоре), напр. iostat -dmx sda 1
sar (System Activity Report, часть пакета sysstat), напр. sar -f /var/log/sa/sa03 -b -s 02:00:00 -e 02:30:00 -r -S
dstat, напр. dstat -cdngy

А вот скриптик для анализа памяти:
#!/bin/bashgrep -A3 "MemTotal" /proc/meminfo  grep "Swap" /proc/meminfogrep -A1 "Dirty\|Active" /proc/meminfo
.

Starting with Pg where is the config?

Депеш (Хуберт Любашевски) в короткой заметке напоминает, как можно найти конфигурационные файлы, если они лежат в нестандартном месте. Способы, которыми он предлагает воспользоваться не сенсационны, но может быть полезен, скажем, удобный набор опций.
Например, так:
ps -fxao pid,command | grep -E 'post(gres|master)'
на выходе будет path. И отсюда:
sudo grep -E '(hba|ident)\.conf' <путь к postgresql.conf>
Или теперь танцуем от pid:
sudo cat /proc/<подставляем pid>/environ | tr '\0' '\n' | grep ^PG | sort
Или:
sudo lsof -p <подставляем pid> -a -d cwd
получаем каталог данных и сведения о нём.
Если такие советы не понадобились, можно порефлексировать на тему я бы сделал по-другому. Скажем, просто-напросто используя find, например.

Агрегаты в БД

Кирилл Боровиков aka kilor завершил мини-серию статей про агрегаты:

Зачем, как, а стоит ли?

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

Эффективная обработка потока фактов

как обработать БОЛЬШОЕ (капслок kilor-а) количество записей и при этом особо никого не заблокировать, включая набегающий поток данных. Например, это может быть пересчет остатков и ведение сводных продаж по товарам при их постоянных отгрузках, или агрегация сальдо и оборотов по бухгалтерским счетам, при массовых изменениях проводок.

Многомерные суперагрегаты

иерархичные агрегаты в нескольких одновременных разрезах;

Прокси-таблицы

как можно снизить суммарные задержки на вставку множества изменений в таблицы агрегатов за счет использования промежуточных таблиц и внешней обработки.



Облака



Babelfish: the Elephant in the Room?

Русский перевод названия этой статьи, появившейся на сайте фонда испаноговорящего сообщества FUNDACIN POSTGRESQL звучал бы так: "Вавилонская рыбка или слона-то я и не приметил?" Мы уже упоминали, что идея проекта сверхамбициозная: Bablefish это PostgreSQL, совместимый с SQL Server настолько, что приложения, под него написанные (в том числе с T-SQL и протоколом TDS), будут сразу работать, не зная, что работают с PostgreSQL.

Автор статьи Альваро Эрнандес (lvaro Hernndez Tortosa, OnGres) начинает с рыночной конъюнктуры, чтобы дальше предъявить гамлетовский вопрос, которым авторы Вавилонской Рыбки должны были задаться: форкать или не форкать?

Babelfish пока не может работать как расширение без доработки ядра PostgreSQL. Альваро напоминает, что 25-го января заслуженный и авторитетный в сообществе человек Ян Вик (Jan Wieck) предложил обсудить расширяемость протокола PostgreSQL: сделать такие хуки, которые позволят реализовать протокол SQL Server в виде расширения без изменений в ядре. Но это процесс небыстрый. Заодно решили обсудить и совместимость с MySQL. Но что делать AWS с Bablefish, если сообщество проигнорирует этот путь или интеграция пойдёт ни шатко, ни валко? Вероятней всего, считает Альваро, AWS будет развивать Bablefish как форк (так уже случилось с Aurora), как бы им не хотелось бы обойтись без форка. А если всё же придётся, то AWS это по силам.

Далее Альваро привлекает Дилемму инноватора. И задаёт ещё один интересный вопрос: хотим ли мы (то есть сообщество), чтобы Babelfish стала MariaDB у PostgreSQL?

Персона


Очередной PG-персоной недели стал Александр Сосна, живущий в небольшом городке на Нижнем Рейне и в свободное от работы в credativ время преподающий ИТ-безопасность в Нижнерейнском Университете. Он работает над довольно необычным расширением: pg_snakeoil. Это антивирус специально для PostgreSQL: он ищет вирусы в данных так, чтобы не мешать работе базы, что отнюдь не характерно для обычных антивирусов. Как замечает Александр, за вирусами охотятся не всегда из-за их вредоносности, иногда только потому, что этого требуют нормативные документы.

Релизы


PostgreSQL 13.2

Вышли PostgreSQL 13.2, 12.6, 11.11, 10.16, 9.6.21, 9.5.25 (последний выпуск ветки 9.5). В этих релизах одолели две проблемы безопасности:
в PostgreSQL 13 можно было, имея права на SELCT одного столбца, получить при помощи изощрённого запроса все столбцы таблицы;
вторая проблема касалась версий 11, 12 и 13. Если у пользователя есть права на UPDATE партицированной таблицы, но нет прав на SELECT некоторого столбца, он мог получить данные столбца из сообщений об ошибке.
Кроме того исправлено более 80 багов.

pg_probackup 2.4.9

Появился флаг --force для инкрементального режима. Теперь можно переписывать содержимое в каталоге, указанном в PGDATA, если system-identifier в целевом экземпляре и копии НЕ совпадают (раньше приходило сообщение об ошибке).


pgAdmin 4 v. 5.0

В версии 5.0 среди прочего появилась поддержка логической репликации; поддержка публикаций и подписок в Schema Diff.

Apache AGE 0.3.0

Apache AGE это расширение, добавляющее в PostgreSQL функциональность графовой базы данных. Цель проекта единое хранилище для реляционной и графовой моделей данных, чтобы пользователи могли использовать и стандартный SQL, и языки запросов к графовым базам openCypher и GQL.

Подробнее..

Postgresso 30

05.04.2021 18:06:45 | Автор: admin

Мы продолжаем знакомить вас с самыми интересными новостями PostgreSQL. Этот выпуск получился с некоторым уклоном в средства диагностики. Нет, не только. Например:

Хардверные ускорители: FPGA


В небольшом сообщении Энди Эликотта (Andy Ellicott) в блоге Swarm64 3 hardware acceleration options Postgres users should know in 2020 рассказывается о трёх аппаратных ускорителях, не GPU, а FRGA, и все они в облаках. У автора свой интерес: у Swarm64 есть собственное решение на FPGA-ускорителе. Значимым сигналом он считает объявление Amazon об FPGA-ускорителе кэша (FPGA-powered caching layer) в Redshift AQUA (Advanced Query Accelerator) в Amazon, который убыстряет запросы на порядок. А вообще уже почти все облака (во всяком случае Amazon, Alibaba, и Azure) используют сейчас FPGA-ускорители, просвещает нас Энди.

Итак:

Swarm64 Data Accelerator (DA)
это расширение, которое умеет переписывать обычные SQL-запросы, чтобы распараллеливать вычисления на всех этапах их исполнения, а сотни читающих или пишущих процессов будут работать параллельно на FPGA. Кроме того, там реализованы индексы columnstore, как в MS SQL Server. Есть техническое описание в PDF, но именно про FPGA в нём ничего нет. Зато есть демонстрационное видео, показывающее, как можно легко и быстро развернуть Postgres на инстансе Amazon EC2 F1 с FPGA. Ещё есть результаты тестов TPC-H (а позиционируется эта комбинация с FPGA прежде всего как ускоритель для гибридных транзакционно-аналитических нагрузок HTAP), и там показывает выигрыш в 50 раз по скорости.

Другой вариант, который предлагает Энди: Intel Arria 10 GX FPGA в связке с NVM-памятью Intel Optane DC, SSD и PostgreSQL 11 с тем же расширением Swarm64 DA. Всё это собрано в демо, которое вбрасывает в PostgreSQL потоки биржевых котировок со скоростью 200 тыс инсертов в секунду, и дальше работает с ними с обычным SQL.

Третий вариант с Samsung SmartSSD, в которой внутри FPGA-чип от Xilinx. Испытания (с тем же свормовским расширением, как можно догадаться) дали выигрыш в 40 раз на TPC-H и в 10-15 раз на JOIN-ах.

С маркетинговой точки зрения эти усилия нацелены прежде всего против хардверных решений для WH вроде Netezza или Teradata.

Обещано, что будет и сравнение эффективности FPGA vs. GPU (в т. ч. и в контексте проекта PGStrom).

(спасибо Александру Смолину за наводку в FB-группе PostgreSQL в России)




Конференции


были:

PGConf.online

Теперь выложены все видео и презентации доступ через расписание.

FOSDEM 21

Поток PostgreSQL devroom тёк два дня 6-7 февраля с 10 утра до 6 вечера. Материалов конференции очень много. Вот имеется однобокая, зато систематизированная выборка доклады от Postgres Professional (глаголы будущего времени там надо поменять в уме на глаголы прошедшего).

будет:

Highload++

Объявлено, что состоится офлайн 17 -18 мая 2021 в Крокус-Экспо, Москва. Есть Расписание. Я бы обратил особое внимание на потоки
СУБД и системы хранения, тестирование в Зале 3, например:
Микросервисы с нуля, Семен Катаев (Авито);
Прокрустово ложе или испанский сапог мифы и реальность СУБД в Облаках, Александр Зайцев (Altinity)
и на
Архитектуры, масштабируемость, безопасность в Зал 4 (главном), например:
Архитектура процессора Эльбрус 2000, Дмитрий Завалишин (Digital Zone);
SQL/JSON в PostgreSQL: настоящее и будущее, Олег Бартунов (Postgres Professional);
Распространённые ошибки изменения схемы базы данных PostgreSQL, Николай Самохвалов (Postgres.ai).

Вебинары и митапы


RuPostgres-вторник s02e13 Андрей Зубков (PostgresPro) pg_profile, pgpro_pwr

Вторник, посвященный pg_profile / PWR, так заинтересовал устроителей, что с большой вероятностью в ближайшее время можно ожидать продолжения: разобрались не во всех тонкостях работы этого весьма практичного инструмента, ну а расширения pgpro_stats, которое используется в PWR, коснулись по касательной.

После это был ещё вторник с Александром Кукушкиным (Zalando). Тема риски апгрейда мажорных версий с фокусом на PG12 и PG13, а пособник апгрейда Spilo: как выяснилось, бесшовный апгрейд в контексте Patroni задача слишком амбициозная, а вот Spilo, то есть Docker-образ с PostgreSQL и Patroni, с задачей справляется. Но опасностей и нюансов при апгрейде остаётся немало. Говорилось о сюрпризах от VACUUM, ANALYZE, о параллелизме по умолчанию, о CTE и материализации, о JIT.

Database Delivery: The Big Problem

Это была презентация от Ростелеком-ИТ, которую провёл Роман Гордеев (в видео глюки, надо прокрутить первые 11 минут). Его пригласили на один из стримов Tver.io сообщества тверских айтишников (но мне удобней было смотреть этот же ролик на на youtube). Речь шла об инкрементальной стратегии миграции. Роман рассказывал о вещах, применимых к разным СУБД и средам разработки, но для примера был выбран переход с базы PostgreSQL на H2 в графическом DataGrip. Соответственно в реальном времени наблюдались и решались проблемы с постгресовым типом text и с последовательностями.

В качестве механизма, который контролирует миграцию, был взят плагин liquibase для среды gradle. О настройках для такой работы можно почитать на страничке liquibase gradle на гитхабе Гордеева. Кстати, Ростелеком Информационные Технологии компания с населением под 2 тыс. человек. На официальной странице есть информация об опенсорсной СУБД in-memory Reindexer собственной разработки. Больше о базах там ничего пока найти не удалось.


Обучение


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

Тем, кто интересуется более пристально, советую прослушать доклад о курсах Егора Рогова на PGConf.online 2021.


Мониторинг


Monitoring PostgreSQL with Nagios and Checkmk

Пишет опять Хамид Ахтар (Hamid Akhtar, китайская компания High Go), на этот раз пишет о средствах мониторинга Nagios (рекурсивный акроним Nagios Ain't Gonna Insist On Sainthood Nagios не собирается настаивать на святости, в отличие от его предшественника NetSaint) и Checkmk. Публикация без претензий: как установить и настроить, не претендуя даже в этом на полноту.

Explaining Your Postgres Query Performance

Идём от простого к сложному. Пока URL подсказывает возможный подзаголовок статьи: Get Started with EXPLAIN ANALYZE. Кэт Бэтьюйгас (Kat Batuigas, Crunchy Data) действительно знакомит с самыми азами EXPLAIN, даже без опций. Жанр For dummies, и наглядно: показывает, как с помощью EXPLAIN ANALYZE можно наблюдать решения планировщика об (не)использовании индексов, и вообще что там происходит. Иллюстрируется это всё на базе Geonames.

Предыдущая её статья была о Query Optimization in Postgres with pg_stat_statements.

Вот ещё одна её статья: Three Easy Things To Remember About Postgres Indexes. В ней не только напоминания о том, что индекс занимает место на диске, но и, например, такие соображения:
Важен и тип запроса. Например, если в запросе есть знаки подстановки (wildcards)
wildcards, e.g. WHERE name LIKE 'Ma%',
то планировщик задействует по умолчанию индекс B-tree, но вам, возможно, стоит указать класс оператора, чтобы был выбран эффективный индекс.

Can auto_explain (with timing) Have Low Overhead?

Михаэль Христофидес (Michael Christofides) показывает работу расширения auto_explain с включённым и отключённым таймингом. Выводы:

Если задать ощутимый промежуток времени min_duration, издержки от auto_explain на небольшой транзакционной нагрузке )была меньше 1% с отключённым таймингом и ~2% с включённым. Семплинга не было, поэтому детали прослеживались для каждого запроса, но попадали в лог для медленных. А когда min_duration=0ms, и логировалось всё, издержки оказались больше 25%, даже без тайминга и ANALYZE. Видимо, издержки auto_explain связаны в основном с логированием.

Интерес у Михаэля не невинный он разработчик утилиты pgMustard, которая визуализирует планы. Она также расписывает, сколько тратится времени и сколько строк возвращает каждая операция (в т.ч. циклы; дочерние узлы планов subplans; CTE). Мало того, pgMustard умеет подсказывать. Например:
  • (не)эффективность индексов;
  • плохая оценка числа строк;
  • неэффективность кэша;
  • угроза распухания индекса (bloat);
  • CTE-скан использовался только 1 раз.


How to create a system information function in PostgreSQL

Давид Ян (David Zhang, старший системный архитектор в той же High Go) делится опытом написания собственных информационных функций. Ему мало тех, что можно найти на вот этой странице. Например, его не устраивает, что txid_current() возвращает ему тот же идентификатор транзакции, что и было до SAVEPOINT.

Ссылаясь на страничку Исходные данные системных каталогов, Давид показывает, как выбрать OID для новой функции, чтобы он не конфликтовал с существующими. Потом приводит код своей функции, определяющей xtid после SAVEPOINT. Называется она txid_current_snapshot и написана на C. И тестирует её. Теперь идентификатор транзакции показывается корректно.

How The PostgreSQL Optimizer Works

Ханс-Юрген Шёниг (Hans-Jrgen Schnig, Crunchy Data) написал не то, чтобы концептуальную, но большую по объёму статью, в которой есть примеры, демонстрирующие:

обработку констант: почему
WHERE x = 7 + 1
для оптимизатора не то же, что
WHERE x - 1 = 7

встраивание функций (function inlining): умение оптимизатора встраивать функции зависит от языка, в SQL он как дома, но не в PL-ях.

как обрабатываются функции, если они VOLATILE/STABLE/IMMUTABLE. Например:
WHERE x = clock_timestamp()
против
WHERE x = now()

что способен понять PostgreSQL, задумавшись о том, что чему равно:
понять, что если x = y AND y = 4, то x = 4, а значит можно использовать индекс по x это он может.

что такое view inlining и subselect flattening:
как представление превращается во вложенные SELECT-ы, а они в обычный, плоский SELECT.

Ну и, конечно, центральный вопрос как оптимизатор расправляется с JOIN. Тут Ханс-Юрген рассказывает об очерёдности джойнов, о явных и неявных; об OUTER JOIN; автоматическом исключении (pruning) ненужных; об EXIST и анти-джойнах.



Случайности:


Они не случайны

Кирилл Боровиков ака kilor выступил в роли волшебника: он угадывает случайные числа! Он придумал волшебную функцию и даже назвал её magic(). В качестве аргумента она берёт только что сгенерённое функцией random() число и предсказывает следующее:
SELECT r random, magic(r) random_next FROM random() r;       random       |    random_next--------------------+-------------------- 0.3921143477755571 | 0.6377947747296489tst=# SELECT r random, magic(r) random_next FROM random() r;       random       |    random_next--------------------+-------------------- 0.6377947747296489 | 0.5727554063674667

Чтобы исследовать содержание внутренностей волшебной функции, автор предлагает разобраться в линейном конгруэнтном алгоритме, который используется в random(), залезает в код функции setseed() в файле float.c и там находит источник вдохновения для создания своей волшебной функции.

Итого, случайные числа random() не слишком случайны, о криптографии и речи не может быть. Но кое-какие альтернативы имеются: более безопасны функции в расширении pgcrypto.


Восстановление


Speeding up recovery & VACUUM in Postgres 14

Статья на сайте Citus, но речь не о Citus, а о патче в основную ветку PostgreSQL. Написана статья (и патч) Дэвидом Роули (David Rowley), работавшим над этим уже внутри Microsoft. Он переписал внутреннюю функцию compactify_tuples, которая используется, когда PostgreSQL стартует после внештатного (нечистого) шатдауна (crash recovery), и когда идёт восстановление standby-сервера проигрыванием WAL по их прибытии с primary-сервера; VACUUM.

Эти случаи Дэвид и расписывает, поясняя схемами. Новая версия функции избавляет от ненужной внутренней сортировки кортежей в heap, поэтому и работает быстрее. На pgbench выигрыш в 2.4 раза на восстановлении и на 25% при вакууме.


Соревнования


Performance differences between Postgres and MySQL

В сообществе Arctype очень интересуются сравнительной производительностью PostgreSQL и MySQL. Эта сумбурная статья с приятными выводами продолжение вот этой, где преимущества той и другой СУБД оценивали качественно, и пришли в том числе к выводам о преимуществах PostgreSQL. Он лучше когда:
  • надо работать со сложно устроенными или объёмистыми данными;
  • аналитические нагрузки;
  • нужна транзакционная база общего назначения;
  • требуется работа с геоданными.


А на этот раз решили померить, причём с уклоном в JSON, поскольку эта тема интересует в сообществе очень многих и очень сильно. Вот что было сделано:
создан проект, в котором использовались PostgreSQL и MySQL;
создали объект JSON для тестирования чтения и записи, размер объекта около14 МБ, около 200210 записей в базе данных.

И опять приятный вывод:
JSON-запросы быстрей в Postgres!

Кроме этого автор по касательной упоминает индексы по выражениям и прочие, особенности репликации, принципиальные отличия MVCC в InnoDB MySQL и в PostgreSQL.


PostGIS


Traveling Salesman Problem With PostGIS And pgRouting

У Флориана Надлера (Florian Nadler, Cybertec) проблемный коммивояжер странствует по окрестностям Гамбурга. Это продолжение статьи 'Catchment Areas' With PostgreSQL And PostGIS. Там собрали множества городов, ближайших к крупным аэропортам, разбросав их по диаграммам Вороного.

Теперь, надо решить, как лучше эти города обойти, для чего кроме PostGIS Флориан использует функции расширения pgRouting. Чтобы превратить множество точек в граф, он выбирает утилиту osm2po.

Дальше pgr_createverticestable функция из pgRouting превратит граф в таблицу. Эта таблица-граф накладывается как слой поверх слоёв OpenStreetMap. После этого Флориан, используя функцию pgr_dijkstraCostMatrix из pgRouting, решает эту знаменитую задачу оптимизации с помощью замысловатого запроса с CTE, учитывая стоимости/веса, присвоенные ещё osm2po.

Performance Improvements in GEOS

GEOS важнейшая для геовычислений библиотека (алгоритмы портированы на C из Java Topology Suite или JTS). Crunchy Data вкладывают в её развитие не меньше сил, чем в саму PostGIS.

Пол Рамси ( Paul Ramsey) рассказывает не просто о тестах производительности GEOS (довольно специфических), а взглядом историка GEOS иллюстрирует ими хронологию улучшений в этой библиотеке от релиза 3.6 к свежайшему 3.9. Вообще-то, о GEOS 3.9 Пол говорил и раньше в начале декабря в блоге Crunchy Data Waiting for PostGIS 3.1: GEOS 3.9 и в собственном. Там тоже есть роскошные иллюстрации, но нет графиков производительности.

А вот заметку Пола Рамси Dumping a ByteA with psql можно увидеть только в его блоге. Она короткая, но может оказаться полезной тем, кто:
  • хранит двоичные файлы в столбцах базы, например изображения-ярлычки (thumbnails);
  • хочет сформировать на выходе двоичный файл изображения, песни, protobuf или LIDAR-файл;
  • использует двоичный формат для транзита двух разных типов.

Хранить в двоичном виде картинку можно, а вот посмотреть нельзя нужен файл. Вот скриптик, который берёт из базы ярлычок в типе bytea, через psql двоичное значение обертывается функцией encode и выгружается как обычное текстовое. Вывод psql перенаправляется в утилиту xxd, которая декодирует входной поток (ключ -r) обратно в двоичный вид и записывает в файл .png:
echo "SELECT encode(thumbnail, 'hex') FROM persons WHERE id = 12345" \  | psql --quiet --tuples-only -d dbname \  | xxd -r -p \  > thumbnail.png

Такой способ будет работать для любого поля bytea.


Активная жизнь в коммьюнити


How many engineers does it take to make subscripting work?

Дмитрий Долгов (Zalando) пишет в своём личном блоге в смешанном жанре: о довольно сложных и специальных технических проблемах самого патча, но и извлекает из истории их решения этакую мораль для писателей патчей. Таких, чтобы сообщество PostgreSQL было в состоянии принять их за время меньше бесконечности.

Патч добавляет subscripting в синтаксис функций JSONB то есть как у массивов, например:
SET jsonb_column['key'] = '"value"';
вместо
SET jsonb_column = jsonb_set(jsonb_column, '{"key"}', '"value"');

Началась история этого патча в 2015 году с беседы Дмитрия с Олегом Бартуновым и последовавшего простенького патча Долгова. Сообщество отнеслось к патчу сочувственно, но предложило переписать его в более универсальной манере, чтобы подобную функциональность можно было бы использовать и для других типов данных. Соответствующий патч Дмитрия был непрост, и ревюеры не торопились его разобрать и оценить. Ещё в истории этого патча фигурируют Том Лейн (Tom Lane), закоммитивший финальный патч Александр Коротков, Павел Стехуле (Pavel Stehule) и Никита Глухов.

Затрагиваются темы универсальности и, пожалуй, лучшее враг хорошего. Патч продвигался настолько вяло, что Дмитрий в отчаянии даже написал в комментарии к патчу: если вы дочитали до этой фразы и напишете рьвю, я выставлю бутылку пива на следующей PGConfEU (о судьбе бутылки из статьи мы не узнали).

В финале статьи 8 советов. Вот некоторые из них в моём вольном переводе, начиная с последнего Last but not least:

Сделать ревю патча требует существенных усилий, поэтому не стесняйтесь тратить усилия, делая ревю патчей ваших коллег.

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

Разбейте патч на несколько частей это всегда облегчает работу ревьюеров.

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


Облака и контейнеры


Running Postgres In Docker Why And How?

Каарел Моппел (Kaarel Moppel, Cybertec) задаёт себе вопрос можно и нужно ли использовать PostgreSQL в Docker в качестве продакшн, будет ли он вообще там работать? и отвечает: да, работать будет, если сильно постараться, и если для фана или для тестирования.

В статье несколько разделов, но начнём с предпоследнего Капли дёгтя в бочку мёда.

Докер-имиджи да и вся концепция контейнеров оптимизированы под моментальное разворачивание в стиле стартапов . По умолчанию там даже данные не разведены как следует по томам (persistent units). Если этого не сделать, затея может закончится катастрофой.

От использования контейнеров не ждите автоматических или каких-то волшебных средств высокой доступности.

У вас будет относительно лёгкая жизнь только в том случае, если вы используете такой всеобъемлющий фреймворк, как Kubernetes плюс выбираете оператор (скорее всего от Zalando или Crunchy).



Поведение


The PostgreSQL Community Code of Conduct Committee Annual Report for 2020

Этот документ сообщества переводили на русский Анастасия Лубенникова, Александр Лахин и Анастасия Распопина (все из Postgres Professional), также участвовали Виктор Егоров и Валерия Каплан. Ещё он переведён с английского на японский и иврит.

Число жалоб увеличилось в 2020: 18 против 12 в прошлом году. Мужчины жалуются чаще: 15/3. Обычно от страны по жалобе. По 2 только от РФ, Аргентины, UK и US.
Подробнее..

Pg_obfuscator обфускатор для postgres с сохранением распределения данных (на основе clickhouse obfuscator)

07.04.2021 12:05:29 | Автор: admin

Введение

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

Наш клиент - klara.com - коммуникационная телемедицинская платформа, упрощающая взаимодействие пациентов с врачами в США, столкнулась со стремительным ростом на волне пандемии 2020 года. Одним из вызовов на которые пришлось отвечать инженерам klara.com в это непростое время стало автоматизированное нагрузочное тестирование, способное обнаружить проблемы с производительностью до того как они проявят себя в production среде.

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

Постановка задачи выглядела так: спроектировать и реализовать пайплайн нагрузочного тестирования таким образом, чтобы его можно было легко поддерживать силами QA-инженеров, использовать как часть CI/CD процессов компании, расширять по необходимости и иметь возможность реализовать различные сценарии нагрузочного тестирования. Критерием успешности проекта стала точная реализация одного из кейса по производительности из production в среде нагрузочного тестирования с помощью инструментов, которые мы разработали.

Технологическая платформа

Основные языки программирования в команде - Ruby, JS. В качестве основного хранилища klara.com использует Postgres. Безопасность персональных данных пациентов (PHI - Protected Health Information) является ключевым аспектом бизнеса klara.com. Для обеспечения надежного хранения и обработки данных платформа использует HIPPA совместимую SaaS платформу - Aptible. Aptible покупает ресурсы у AWS, поэтому для дальнейшего описания будет достаточно считать Aptible сильно урезанной и зарегулированной версией AWS.

Для максимально корректной реализации нагрузочного тестирования нам нужна среда максимально похожая на production среду. Идеально, если идентичными будут: серверный парк, структура и объем данных, версии кода, структура и объем трафика. Очевидно также, что сделать все перечисленное абсолютно идентичным за разумное время и бюджет не реально и всегда приходится принимать некие допущения.

В этой статье я расскажу как мы готовили данные для нагрузочного тестирования.

Чтобы воспроизвести похожее поведение приложения во время тестов нам нужно иметь максимально похожую на production базу данных с точки зрения объема данных и их распределения. Из-за того, что klara хранит в том числе персональные данные, нам понадобится обфускация базы. Дополнительное условие - скорость работы обфускатора, хотелось бы быстро.

Обзор решений

Сейчас существует несколько инструментов для решения этой задачи в postgres, мы провели краткий сравнительный анализ, который приведен ниже:

postgresql_anonymizer

+ Самое популярное по количеству звезд на github решение из имеющихся

+ Очень много функций для разных типов данных с разными стратегиями, которые можно применять точечно для выбранных полей (http://personeltest.ru/aways/postgresql-anonymizer.readthedocs.io/en/latest/masking_functions/)

+ Можно выгружать сразу в *.sql дамп

- Нужно устанавливать как расширение рядом с бд

- Для каждого поля нужно прописывать security labels с масками

- Маски работают только с одной схемой

- Нет данных по производительности

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

triki

+ Заявлена высокая скорость работы (1.4гб mysql dump 17sec)

+ Много типов данных + можно определить свои (форк + правки т.к. кристал руби-френдли язык)

+ Можно выгрузить конфигурацию всей схемы для дальнейшей настройки обфускатора (таблицы-поля)

+ Не требуется никаких правок в исходной бд, только настроить коннект

+ Выгружает в *.sql дамп

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

pgdump-obfuscator (форк)

+ есть возможность задавать параметры полей через cli (только в форке)

- нет информации о производительности

- обновлялся 8 лет назад

clickhouse-obfuscator

+ Заявлена высокая скорость работы (в докладе говорилось, что 1тб данных обфусцирован за 1.5 дня)

- Написан на C++ (нашей команде сложно вносить изменения)

- Принимает только csv-формат

- Нет внятной документации (только статья на Хабре)

Высокая скорость, сохранение распределения данных после обфускации, поддержка большой компанией и комьюнити - по этим причинам мы выбрали обфускатор от clickhouse.

pg_obfuscator

К сожалению для нашей задачи, clickhouse obfuscator не поддерживал прямое подключение к postgresql. Поэтому нам пришлось написать утилиту, которая решает задачу обфускации postgresql с учетом всей специфики работы именно с этой базой. Исходный код доступен по адресу.

Утилита представляет собой wrapper над psql client и clickhouse obfuscator и реализует следующую функциональность

  • выгрузка схемы базы с сохранением внешних ключей и проверок ссылочной целостности

  • исключение из обфускации таблиц, полей таблиц

  • использование предопределенных шаблонов для генерации фейковых значений для полей

  • маппинг типов данных postgres на типы данных clickhouse

  • генерацию конфигурации со значениями по умолчанию

Из-за специфики работы clickhouse-obfuscator утилита требует дискового пространства для работы равного двойному размеру базы данных. Поставляется в виде docker image и доступна по адресу.

В настоящий момент есть ограничения, которые следует иметь в виду:

  • утилита поддерживает только базовые типы postgres и не поддерживает вложенные: hstore, json, jsonb

  • несмотря на автоматическую генерацию конфига, для первого запуска он нуждается в правках

  • объем docker image составляет почти 700Mb

В рамках поставленной задачи мы наблюдали следующие скоростные характеристики: тестовая база 10Гб обфусцировалась за 40 минут, продуктовая в 50 Гб - 6..8 часов. Чем обусловлена нелинейность работы мы не выясняли.

Ниже я продемонстрирую работу c pg_obfuscator на примере работы с devrimgunduz/pagila: PostgreSQL Sample Database.

Демо

Развернем контейнер с postgres и создадим в нем 2 базы для демонстрации:

docker run --rm --name=db -e POSTGRES_PASSWORD=password -p5432:5432 postgresdocker exec -i db psql -U postgres postgres -c 'create database pagila;'docker exec -i db psql -U postgres postgres -c 'create database pagila_o;'

Посмотрим IP-адрес базы - он понадобится для работы обфускатора:

docker inspect db | grep IPAdd

"SecondaryIPAddresses": null,

"IPAddress": "172.17.0.2"

И зальем в контейнер скрипты из проекта pagila:

cd /tmpgit clone git@github.com:devrimgunduz/pagila.gitdocker exec -i db psql -U postgres pagila < /tmp/pagila/pagila-schema.sqldocker exec -i db psql -U postgres pagila < /tmp/pagila/pagila-data.sql

Убедимся, что там появились данные:

docker exec -i db psql -U postgres pagila -c 'select a.first_name, a.last_name, f.film_id, f.title, f.description from film f join film_actor fa on f.film_id = fa.film_id join actor a on a.actor_id=fa.actor_id where f.film_id = 7;'

first_name | last_name | film_id |   title   |                  description------------+-----------+---------+-----------------+-----------------------------------------------------------------------------------JIM    | MOSTEL  |    7 | AIRPLANE SIERRA | A Touching Saga of a Hunter And a Butler who must Discover a Butler in A Jet BoatRICHARD  | PENN   |    7 | AIRPLANE SIERRA | A Touching Saga of a Hunter And a Butler who must Discover a Butler in A Jet BoatOPRAH   | KILMER  |    7 | AIRPLANE SIERRA | A Touching Saga of a Hunter And a Butler who must Discover a Butler in A Jet BoatMENA    | HOPPER  |    7 | AIRPLANE SIERRA | A Touching Saga of a Hunter And a Butler who must Discover a Butler in A Jet BoatMICHAEL  | BOLGER  |    7 | AIRPLANE SIERRA | A Touching Saga of a Hunter And a Butler who must Discover a Butler in A Jet Boat(5 rows)

База для экспериментов готова. Теперь расчехлим pg_obfuscator, принципиальным моментом является монтирования тома для конфига, чтобы иметь возможность его потом поправить.

mkdir /tmp/configdocker run -it --rm -v /tmp/config:/opt/pg_obfuscator/config pg_obfuscator sh

Дальше команды выполняются в шелле обфускатора, если не сказано другого:

bundle exec ruby pg_obfuscator.rb --configure --source-db-host 172.17.0.2 --source-db-port 5432 --source-db-name pagila --source-db-user postgres --source-db-password password.......I, [2021-04-02T08:47:54.682868 #9] INFO -- : Processed 20 tablesI, [2021-04-02T08:47:54.683243 #9] INFO -- : Check config before run export tables and obfuscation!I, [2021-04-02T08:47:54.696328 #9] INFO -- : Config saved to: config/config.yml

Обфускатор говорит, что нужно проверить конфиг и внести необходимые изменения. Конфиг для 20 таблиц получился около 400 строк, секции, которые нуждаются в правках отмечены - need_fix: true. Для того, чтобы вам было легче повторить я выложил исправленный конфиг сюда.

Для демонстрации генерации фейковых данных посмотрим на секцию в таблице actor:

last_name:db_data_type: textnot_null: trueobfuscator_data_type: Stringfake_data:type: patternvalue: "%{first_name}SON"

В качестве фамилии мы используем имя и постфикс SON.

Выполним последовательно экспорт схемы, данных, обфускацию и заливку полученных данных в базу pagila_o

ruby pg_obfuscator.rb --export-schema --source-db-host 172.17.0.2 --source-db-port 5432 --source-db-name pagila --source-db-user postgres --source-db-password passwordruby pg_obfuscator.rb --export-tables --source-db-host 172.17.0.2 --source-db-port 5432 --source-db-name pagila --source-db-user postgres --source-db-password passwordbundle exec ruby pg_obfuscator.rb --obfuscateruby pg_obfuscator.rb --import --target-db-host 172.17.0.2 --target-db-port 5432 --target-db-name pagila_o --target-db-user postgres --target-db-password password

и выйдя из контейнера с обфускатором посмотрим на результат

docker exec -i db psql -U postgres pagila_o -c 'select  a.first_name, a.last_name, f.film_id, f.title, f.description from film f join film_actor fa on f.film_id = fa.film_id join actor a on a.actor_id=fa.actor_id where f.film_id = 7;'
first_name | last_name | film_id |  title  |                           description------------+-----------+---------+-----------+------------------------------------------------------------------------------------------------------------------------SA     | SASON   |    7 | ROON SUIT | A Amazing Display of a Database Administ And a Dog And a Database a Pastry Chef And a Car And a Manned Mine Shark TankRURA    | RURASON  |    7 | ROON SUIT | A Amazing Display of a Database Administ And a Dog And a Database a Pastry Chef And a Car And a Manned Mine Shark TankBER    | BERSON  |    7 | ROON SUIT | A Amazing Display of a Database Administ And a Dog And a Database a Pastry Chef And a Car And a Manned Mine Shark TankCA     | CASON   |    7 | ROON SUIT | A Amazing Display of a Database Administ And a Dog And a Database a Pastry Chef And a Car And a Manned Mine Shark TankMER    | MERSON  |    7 | ROON SUIT | A Amazing Display of a Database Administ And a Dog And a Database a Pastry Chef And a Car And a Manned Mine Shark Tank(5 rows)

Видим, что last_name сформирован фейкером, описание обфусцировано, ссылочная целостность сохранена.

На этом все, мы надеемся, что утилита будет полезна сообществу, будем рады видеть пулреквесты.

Благодарим команду clickhouse obfuscator за отличный продукт!

Подробнее..

Как быстрее всего передавать данные с PostgreSQL на MS SQL

21.04.2021 00:08:36 | Автор: admin

Однажды мне потребовалось забирать регулярно относительно большие объемы данных в MS SQL из PostgreSQL. Неожиданно выяснилось, что самый очевидный способ, через Linked Server на родные ODBC к PostgreSQL, очень медленный.


История вопроса

На этапе прототипирования все было хорошо. Просто потому, что протипировалось всего несколько тысяч записей. Как только перешли к разработке, сразу возникло подозрение, что с производительностью что-то не то:

SET STATISTICS TIME ONDECLARE  @sql_str nvarchar(max)DROP TABLE IF EXISTS #tCREATE TABLE #t (  N int,  T datetime)SELECT @sql_str='  SELECT N, T  FROM generate_series(1,1000,1) N  CROSS JOIN generate_series($$2020-01-01$$::timestamp,    $$2020-12-31$$::timestamp, $$1 day$$::interval) T'INSERT #t (N, T)EXEC (@sql_str) AT LINKED_SERVER_TO_POSTGRES

Такой простейший пример выборки всего 366 тысяч записей оказался жутко медленным:

SQL Server Execution Times:   CPU time = 8187 ms,  elapsed time = 14793 ms.

Решение

В первую очередь, захотелось исключить самый подозрительный элемент - ODBC. К тому времени MS уже предоставлял утилиту bcp для Linux. Поэтому bcp был установлен на сервер, где работал PostgreSQL и проведен следующий тест:

SET STATISTICS TIME ONDECLARE  @sql_str        nvarchar(max),  @proxy_account  sysname='proxy_account',  @proxy_password sysname='111111'DROP TABLE IF EXISTS ##tCREATE TABLE ##t (  N int,  T datetime)SELECT @sql_str='  COPY (    SELECT N, T    FROM generate_series(1,1000,1) N    CROSS JOIN generate_series($$2020-01-01$$::timestamp,      $$2020-12-31$$::timestamp, $$1 day$$::interval) T )  TO PROGRAM $pgm$ tmp_file=$'+'(mktemp /tmp/pgsql_bcp_to_mssql.XXXXXXXXX); '    +'cat > $tmp_file; /opt/mssql-tools/bin/bcp ''##t'' '    +'in $tmp_file -S '+REPLACE(@@SERVERNAME,'','\')    +' -U '+@proxy_account+' -P '''    +@proxy_password+''' -c -b 10000000 -a 65535; '    +'rm $tmp_file $pgm$ NULL $nil$$nil$;'EXEC (@sql_str) AT LINKED_SERVER_TO_POSTGRES

Результат сразу порадовал, причем сильно:

SQL Server Execution Times:   CPU time = 0 ms,  elapsed time = 881 ms.

Реализация

Не сложно заметить, что такой подход требует явного указания логина и пароля. Причем, bcp для Linux до сих пор не умеет авторизоваться через Kerberos. Поэтому использовать его можно только указывая кредентиалы в командной строке.

Вторая проблема в том, что в обычную временную таблицу bcp записать не может. Он ее просто не увидит. Значит нужно использовать постоянную таблицу или глобальную временную.

Давать права пользователю, кредентиалы которого открытым текстом видны в SQL запросе, на таблицы своей БД совершенно не хочется. Тем более на запись. Поэтому остается только вариант с глобальной временной таблицей.

В связи с тем, что процессы на сервере могут запускаться асинхронно и одновременно, использовать фиксированное имя глобальной временной таблицы опасно. Но тут нас опять спасает динамический SQL.

Итоговое решение следующее:

DECLARE  @sql_str        nvarchar(max),  @proxy_account  sysname='proxy_account',  @proxy_password sysname='111111'SELECT @sql_str='  DROP TABLE IF EXISTS ##proxy_table_'+CONVERT(nvarchar(max),@@SPID)+'  CREATE TABLE ##proxy_table_'+CONVERT(nvarchar(max),@@SPID)+' (    N int,    T datetime  )'EXEC (@sql_str)SELECT @sql_str='  COPY (    SELECT N, T    FROM generate_series(1,1000,1) N    CROSS JOIN generate_series($$2020-01-01$$::timestamp,      $$2020-12-31$$::timestamp, $$1 day$$::interval) T )  TO PROGRAM $pgm$ tmp_file=$'+'(mktemp /tmp/pgsql_bcp_to_mssql.XXXXXXXXX); '    +'cat > $tmp_file; /opt/mssql-tools/bin/bcp ''##proxy_table_'''    +CONVERT(nvarchar(max),@@SPID)+' '    +'in $tmp_file -S '+REPLACE(@@SERVERNAME,'\','\\')    +' -U '+@proxy_account+' -P '''    +@proxy_password+''' -c -b 10000000 -a 65535; '    +'rm $tmp_file $pgm$ NULL $nil$$nil$;'EXEC (@sql_str) AT LINKED_SERVER_TO_POSTGRES

Пояснения

В PostgreSQL команда COPY может писать в файл или на стандартный ввод вызываемой ей программы. В данном случае вместо программы использован скрипт на sh. Вывод COPY, поступающий на стандартный ввод, записывается во временный файл с уникальным именем, форимруемым mktemp. К сожалению, bcp не умеет читать данные со стандартного ввода, поэтому приходится ему создавать файл.

Для совместимости формата, формируемого командой COPY и формата, ожидаемого bcp, обязательно следует указывать в COPY параметр NULL $nil$$nil$

Остальные параметры bcp:

  • -c - символьный формат, так как бинарный формат PostgreSQL не совместим с бинарным форматом MS SQL и мы вынуждены использовать только символьный;

  • -b - количество записей, вставляемых одной транзакцией. В моей конфигурации десять миллионов оказалось оптимальным значением. В иной конфигурации это число, скорее, может потребоваться уменьшить, чем увеличить;

  • -a - размер пакета. В нашем случае лучше указывать сразу максимальный. Если сервер не поддерживает указанную длину пакета, то просто будет использована максимальная длина пакета, поддерживаемая сервером.

Если кто-то знает более быстрый способ получения данных на MS SQL из PostgreSQL - буду очень рад увидеть описание этого способа в комментариях.

Подробнее..
Категории: Postgresql , Sql , Postgres , Microsoft sql server , Mssql , Bcp

Postgresso 31

11.05.2021 16:15:42 | Автор: admin
Надеемся, что вы хорошо отдохнули и попраздновали. А мы предлагаем вам очередную сводку Postgres-новостей.

PostgreSQL 14 Beta 1


Релизная группа в составе Пит Гейган (Pete Geoghegan, Crunchy Data), Мишель Пакье (Michael Paquier, VMWare) и Эндрю Данстан (Andrew Dunstan, EDB) предлагают опубликовать бету 20-го мая, как это и происходило с предыдущими бетами.



Commitfest afterparty


PostgreSQL 14: Часть 5 или весенние заморозки (Коммитфест 2021-03)

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

Вот авторский тизер:
  • Может ли один запрос параллельно выполняться на разных серверах?
  • Как найти запрос из pg_stat_activity в pg_stat_statements?
  • Можно ли добавлять и удалять секции секционированной таблицы не останавливая приложение?
  • Как пустить разработчиков на прод чтобы они могли всё видеть, но ничего не могли изменить?
  • Почему VACUUM после COPY FREEZE заново переписывает всю таблицу и что с этим делать?
  • Можно ли сжимать TOAST чем-то кроме медленного zlib?
  • Как понять сколько времени длится блокировка найденная в pg_locks?
  • Для чего нужны CYCLE и SEARCH рекурсивному запросу?
  • Текст функций на каких языках (кроме C) не интерпретируется при вызове?


Миграция


CHAR(1) to Boolean transformation while migrating to PostgreSQL

В Oracle нет типа boolean, а в PostgreSQL есть. Но почему бы не использовать этот тип, если в исходной оракловой базе есть столбец boolean, который хранится там в виде CHAR(1) с ограничением CHECK? Можно. Но хотелось бы ещё получить гарантию, что значения, отличные от резрешенных для Postgres не остановят работу приложения, а будут должным образом обработаны. Для этого можно создать CAST:
CREATE CAST (char as bool) WITH FUNCTION char_to_bool(char);
Далее автор Дилип Кумар (Dileep Kumar, MigOps) показывает изменение поведения при определении CAST как IMPLICIT, а потом прогоняет запрос (обычный SELECT) на тестах, чтобы увидеть разницу CHAR(1) vs Explicit Casting vs Implicit Casting vs Boolean. Побеждает, как и ожидалось, Boolean.

Choice of Table Column Types and Order When Migrating to PostgreSQL

В статье Стивена Фроста (Stephen Frost) с участием его коллеги по Crunchy Data Дэвида Юатта (David Youatt) тоже говорится о том, какой тип выбрать в PostgreSQL при миграции, но ещё и о том, в каком порядке располагать столбцы, чтобы данные выбранных типов хранились максимально эффективно. Сначала самые широкие поля с фиксированной шириной, затем менее широкие с фиксированной и только потом поля переменной ширины иначе появятся дыры в данных. Стивен рассказывает и про неприятные сюрпризы с выравниванием, которые можно получить, излишне рьяно экспериментируя с типами PostgreSQL. Ещё совет: выбирайте NUMERIC или DECIMAL только тогда, когда необходимо (считая деньги, например), а если нет, то обходитесь NTEGER, BIGINT, REAL, DOUBLE PRECISION это проще и эффективней.


Масштабирование


Lessons Learned From 5 Years of Scaling PostgreSQL

Джо Уилм (Joe Wilm) обобщает опыт использования PostgreSQL в компании OneSignal. Система доросла за 5 лет до 75 ТБ на 40 серверах. Понятно, что не все технические решения были приняты сразу на вырост. Как решают проблемы масштабирования, и как их можно было избежать об этом и рассказывает автор. Для удобства он разбил статью по разделам (сознательно не перевожу, слишком много английских слов пришлось бы писать кириллицей):
Bloat таблиц и индексов. Коротко о (хорошо известных) причинах распухания. pg_repack справлялся так себе (см. причины), написали собственный демон, координирующий его работу. Перешли к pgcompacttable там, где pg_repack обваливает производительность (перешли не везде, pgcompacttable работает надёжней, но медленней). Есть и об уловках по ситуации: в системе были таблицы, в которых большие поля (около 1 КБ) в личных данных, и поле last_seen_time int, которое часто обновлялось. Их разнесли по разным таблицам: одним JOIN больше, зато не копятся килобайты при обновлении строки.
Database upgrade. Мажорные и минорные. С мажорными справлялись при помощи логической репликации pglogical. При минорых просто перестартовывали postgres.
Wraparound. Серьёзная проблема для таких нагрузок. Остановились на оповещениях при приближении к 250 млн оставшихся XID. Напомним, конечно, что в Postgres Pro Enterprise 64-битные XID.
Replica Promotion. Для этого обходятся средствами haproxy. Упоминается только Patroni, но и то в контексте мы не используем, но может и стоило. Для каждой логической базы данных есть два бэкенда: один read-write, другой read-only. Переключение занимает пару секунд.
Partitioning и Sharding. Важнейшая штука для такой базы, конечно. Сначала порезали на 16 секций, потом на 256, а в ближайших планах 4096. Резали на куски выбирая в качестве критерия разбиения id пользователей системы. Сейчас думают над созданием data proxy слое, который будет знать, как разрезаны данные и где лежат, и действовать соответственно. Чтобы приложениям этого не требовалось знать для нормальной работы. Сетуют, что не сделали так с самого начала.


Самокритика


Чего энтерпрайзу в PostgreSQL не хватает

Вот чего ему не хватает в порядке важности (по Кириллу Боровикову, автору статьи)
  • легковесного менеджера соединений (он же built-in connection pooler);
  • 64-bit XID;
  • микротаблиц (речь о том, что у каждой таблицы и индекса в PostgreSQL есть 3 форка файла, но почему бы не обойтись 1 файлом (heap) для мелких справочных табличек?);
  • zheap;
  • append-only storage (а в идеале, считает Кирилл хотелось иметь возможность назначать часть полей индексов или целых таблиц как no-MVCC чтобы иногда экономить на полях поддержки MVCC);
  • отложенная индексация (чтобы сервер мог размазать необходимые операции во времени для балансировки нагрузки эта тема особенно важна для конкуренции с поисковыми системами, где основная задача найти вообще, а не найти прямо сразу сейчас);
  • columnar storage (в идеале в ядре или в contrib);
  • in-memory storage (очень быстрого нетранзакционного хранилища без сброса на диск);
  • не пухнущих TEMPORARY TABLE, в том числе на репликах;
  • multimaster из коробки;
  • SQL-defined index (уметь описывать новые виды индексов прямо на SQL/PLpgSQL);
  • мониторинга производительности запросов (здесь Кирилл предлагает глянуть, как это визуализируется на родном explain.tensor.ru);
  • снапшотов статистики таблиц (как в pg_profile [а тем более в pgpro_pwr примечание редакции]).

К ЭТОМУ ДОБАВИЛИСЬ ХОТЕЛКИ ИЗ КОММЕНТАРИЕВ:

  • IS NOT DISTINCT FROM при индексации;
  • failover из коробки (аналогично Always on у MS SQL) без Patroni и сопутствующих;
  • Asynchronous IO и Direct IO;
  • бесшовного обновления мажорной версии;
  • flashback queries;
  • edition-based redefinition;
  • нормальной компрессии.

Некоторые из этих хотелок на пути к дальнейшим версиям, некоторые уже есть в Postgres Pro Enterprise (о чём не умалчивает и автор).


Видео-вторник s02e15: Десять проблем PostgreSQL. Мониторинг запросов, pg_profile

(это продолжение вторника ) с Андреем Зубковым)

Статья Рика Брэнсона: (Rick Branson) 10 things I Hate In Postgres внезапно попала в топ обсуждаемых. Вот её не миновали и устроители ruPostgres.Вторников Николай Самохвалов и Илья Космодемьянский.

О ней мы писали в Postgreso 20. На ruPostgres.вторнике s02e15 6-го апреля самые жаркие вопросы возникали, как всегда, вокруг MVCC и VACUUM, переполнения 32-битных счётчиков XID.

На 50-й минуте обсуждения 10 ненавистных вещей Андрей Зубков продолжил рассказал о pg_profile (до pgpro_pwr речь опять не дошла, говорили даже о том, чтобы наверстать в 3-й серии) и о своём патче pg_stat_statements: Track statement entry timestamp (ровно 1:00 записи).

Вторник 20-го апреля назывался Как поменять тип колонки в таблице PostgreSQL с 1 млрд строк без даунтайма?. Два разных варианта решения на уровне колонки и на уровне таблицы.

А совсем недавний 4-го мая о разном, например, о WAL-G vs. pgBackRest, об амазоновских инстансах на ARM, о которых чуть ниже. Список тем лежит в файле.


Облака и контейнеры


Dramatical Effect of LSE Instructions for PostgreSQL on Graviton2 Instances

Александр Коротков в своём блоге пишет об опыте работы с новейшими облаками инстансы Graviton2 работают на амазоновских ARM-процессорах. Но следующие за модой расплачиваются некоторыми сложностями у ARM есть специфика (по мнению Александра работа с ними скорее напоминает работу с IBM Power).

Команды LSE (Large System Extensions), доступные с версии 8.1, действительно ускоряют работу. Вот здесь это разъясняют с некоторыми подробностями, испытывая MySQL на включенных и отключенных LSE. Александр же получил колоссальный выигрыш на pgbench, скомпилировав PostgreSQL 14 с поддержкой LSE. Но это касается только амазоновских ARM AWR Graviton2. Apple M1 не удалось оптимизировать (возможно, в этих процессорах есть какая-то внутренняя оптимизация), а на китайских Kunpeng 920 результаты даже ухудшились.


Что делать


Managing Transaction ID Exhaustion (Wraparound) in PostgreSQL

Кит Фиске (Keith Fiske, Crunchy Data) регулярно пишет в своём собственном блоге Keith's Ramblings о вакууме, распухших индексах и других важнейших для вдумчивого постгресиста вещах.

В этой статье есть конкретные SQL-запросы, использующие autovacuum_freeze_max_age для получения внятной информации о происходящем с конкретными таблицами, так как vacuumdb --all --freeze --jobs=2 --echo --analyze всего кластера баз данных во многих случаях слишком радикальная мера. Если недовакуумированных таблиц очень много, то Кит советует вакуумировать в батчах не больше сотни в каждом. Сам он предпочитает держать max XID < to 50% autovacuum_freeze_max_age, лучше 30-40%.

Он написал статью и о настройке автовакуума: Per-Table Autovacuum Tuning. Но даже аккуратно настроив автовакуум, стоит с не меньшей аккуратностью мониторить ситуацию. Риск не велик, но ставка высока, как говорили наши деды.

Не удержусь от перечисления собственных проектов Кита (или с его существенным участием):
pg_partman расширение с автоматической поддержкой секционирования по времени и serial id;
pg_extractor продвинутый фильтр дампа;
pg_bloat_check скрипт для мониторинга таблиц и индексов;
mimeo расширение PostgreSQL для потабличной логической репликации;
pg_jobmon расширение для логирования и мониторинга автономных функций.

Postgres is Out of Disk and How to Recover: The Dos and Don'ts

Статья Элизабет Кристинсен (Elizabeth Christensen) с участием Дэвида Кристинсена (David Christensen), Джонатана Каца (Jonathan Katz) и Стивена Фроста (Stephen Frost) все из Crunchy Data. Почему забился диск, что НЕ делать, и что делать.
Возможные причины:
  • отказала archive_command и WAL начал заполнять диск;
  • остались слоты репликации у стендбая, а реплика стала недоступна: опять же WAL заполняет диск;
  • изменения в базе настолько большие, что генерящийся WAL съедает всё доступное дисковое пространство;
  • просто-напросто данных было слишком много, а средства мониторинга и предупреждения не сработали.

Что НЕЛЬЗЯ делать:
удалять WAL-файлы нельзя категорически;
  • не дайте переписать существующие данные, восстанавливаясь из бэкапа;
  • Никакого resize.


Что надо делать:
  • сделайте сразу бэкап на уровне файловой системы;
  • создайте новый инстанс (или хотя бы новый том) с достаточным местом, убедитесь, что Postgres остановлен и сделайте бэкап директории данных PostgreSQL (обязательно директории pg_wal и недефолтные табличные пространства), чтобы вам было куда вернуться, если понадобится;
  • когда база данных заработала, просмотрите логи, разберитесь, из-за чего возникли проблемы и почините поломки, если это возможно.

В статье рассказывается, как архивируется WAL, об попорченных архивах, кое-что о pgBackRest, а ещё предлагается почитать How to Recover When PostgreSQL is Missing a WAL File.

Кстати, о WAL. Если нужно порекомендовать хорошую статью англоязычным коллегам, то в блоге Postgre Pofessional опубликован перевод 3-й части серии Егора Рогова о WAL: WAL in PostgreSQL: 3. Checkpoint. Оригинал её здесь, en-начало-серии здесь, а ru-начало здесь.


Из блога БРЮСА МОМДЖАНА


(то есть отсюда)

Jsonb Multi-Column Type Casting

Брюс делится радостью, что есть jsonb_to_record() и можно без всяких двойных двоеточий сразу сказать:
SELECT a, b, pg_typeof(a) AS a_type, pg_typeof(b) AS b_typeFROM test, jsonb_to_record(test.x) AS x (a TEXT, b INTEGER);

(А ведь добавим от себя есть ещё и jsonb_to_recordset(jsonb)).

Брюс обращает внимание на устройство таких запросов. Если сказать
SELECT x.a, b, pg_typeof(a) AS a_type, pg_typeof(b) AS b_typeFROM test, jsonb_to_record(test.x) AS x (a TEXT, b INTEGER)WHERE b <= 4;

то это будет работать, ведь b уже integer потому, что запрос уже создал табличку x с областью видимости только внутри запроса, где типы уже преобразованы. Немногословный (как обычно в своём блоге) Брюс предлагает ознакомиться с деталями в тредах json_to_record Example и Abnormal JSON query performance.

Oracle vs. PostgreSQL

Брюс решил оценить функциональную полноту обеих СУБД в %, в ответ на чьё-то сравнение Postgres и Oracle это как резиновая уточка против танкера водоизмещением 300 тыс. тонн. Он считает:
Более реалистичной была бы оценка в 80-90%, в зависимости от того, какая функциональность для вас важней. Но можно бы поговорить и том, что в Postgres есть, а в Oracle нет. С точки зрения админа получится, может быть, и меньше 80%, а вот с точки зрения разработчика в Oracle нет многого, и оценка перевалит за 100%.

Challenging Assumptions

Следующие, некогда справедливые допущения теперь сомнительны:
  • платный софт всегда лучше бесплатного;
  • открытый код не столь безопасен, так как слабые места видны;
  • серьёзные люди софт с открытым кодом не разрабатывают;
  • Oracle лучшая СУБД;
  • со знанием Oracle без работы я не останусь;

Кто закрывает дыры и латает щели (в оригинале Database Software Bundles)

Проект Postgres дал миру великолепную, полнофункциональную СУБД. Но когда пользователь думает о бэкапе, мониторинге, высокой доступности, ему приходится смотреть на сторону, так как возможности Postgres могут не совпадать с его потребностями. Иногда бреши закрывают проекты с открытым кодом, но в других случаях решают проблемы коммерческие Postgres-компании: Cybertec, edb, HighGo, Ongres, Postgres Pro, sra oss и другие, которые поставляют сервисы последней мили для корпоративных решений.

Также можно заглянуть в

Shared Memory Sizing
или, скажем, в
Replica Scaling by the Numbers


ИИ


Regression Analysis in PostgreSQL with Tensorflow

Дейв Пейдж (Dave Page, вице-президент и главный архитектор EDB) продолжает серию, посвященную ИИ и статистическим методам анализа данных. Из последнего: вышли две статьи посвященные регрессионному анализу, который ускоряют с помощью Tensorflow. В приведенных примерах можно увидеть много ласкающих слух питониста слов: pandas, numpy, matplotlib и seaborn. Подчеркнём, что используется расширение PostgreSQL plpython3u, а не просто внешние по отношению к базе библиотеки.

Во второй части дело доходит до пред-обработки данных. Используется популярный у педагогов машинного обучения набор данных Boston Housing Dataset по ним тренируются угадывать цену дома в Бостоне в зависимости от некоторых факторов. Из набора выкидывают значения, сильно отличающиеся от общей массы, чтобы не запутать нейронную сеть при обучении. Ещё смотрят распределения и строят корреляции. Третья статья ещё не вышла. Обещано, что в ней уже воспользуются достижениями 2-й части, чтобы обучать нейронную сеть регрессионному анализу.


Релизы


Kubegres

Обычно в разговоре о PostgreSQL в Kubernetes на третьей фразе появляются операторы от Crunchy Data и Zalando. Kubegres, возможно, вклинится в разговор. Разработчик Алекс Арика (Alex Arica, Reactive Tech Limited). Создавался Kubegres на базе фреймворка Kubebuilder version 3 (SDK для разработки Kubernetes APIs с использованием CRD. Можно забрать отсюда.

KuiBaDB

KuiBaDB это Postgres для OLAP, переписанный с Rust и многопоточностью. У этой СУБД есть только базовая функциональность. Она, например, поддерживает транзакции, но не вложенные транзакции. KuiBaDB создан для разработчиков, чтобы они могли быстренько проверить на ней свои идеи. В ней есть векторный движок и колоночное хранение, она опирается на каталоги (catalog-driven).

pgBackRest 2.33

Появилась поддержка нескольких репозиториев данные и WAL можно копировать сразу в несколько хранилищ.
pgBackRest поддерживает теперь GCS Google Cloud Storage.
Отныне можно задать путь вручную с ./configure --with-configdir. Стало удобней работать с не-Linux ОС, например с FreeBSD.
Появилось логирование в процессе бэкапа.

pg_probackup 2.4.15

В новой версии pg_probackup при бэкапе в инкрементальном режиме автоматически обнаруживается переключение таймлайнов, за счёт использования команды TIMELINE_HISTORY протокола репликации (предложил Алексей Игнатов).

При операциях merge и retention merge теперь тоже можно использовать флаги --no-validate и --no-sync.

pgmetrics 1.11.0

pgmetrics утилита с открытым кодом для сбора статистики работающего PostgreSQL, распространяемая в виде единого бинарного файла без внешних зависимостей. Разработчик RapidLoop, у которой есть ещё и pgDash, для которой pgmetrics собирает статистику.

Новое в версии:
  • собирает и парсит логи из AWS RDS и Aurora, используя CloudWatch;
  • поддержка пулера Odyssey v1.1;
  • улучшена поддержка Postgres 13;
  • улучшена поддержка метрик AWS RDS;
  • появились бинарники для ARMv8

Скачать можно отсюда.

HypoPG 1.2

HypoPG одно из произведений Жульена Руо (Julien Rouhaud). Это расширение для работы с гипотетическими индексами. Новое в версии: работая на стендбае, hypopg использует фальшивый (fake) генератор oid, который одалживает их внутри интервала FirstBootstrapObjectId / FirstNormalObjectId, а не генерит реальные. Если потребуется, можно работать по-старому, используя опцию hypopg.use_real_oids. Есть и ещё изменения, hypopg_list_indexes(), подробности в документации.

pgstats.dev

Это динамическая диаграмма Postgres Observability упрощенное представление устройства PostgreSQL и доступные системные представления и функции для получения статистики о работе подсистем Postgres. Этому необычному произведению Алексея Лесовского (Data Egret) всего 5 месяцев, но её знают многие DBA, спорят и интересуются: что новенького? Новое, например, вот:
  • стрелки, которые раньше показывали связи между блоками и метками статистики, теперь исчезли, а соответствующие цвета введены, чтобы показать их отношения;
  • на страницах описания статистик (см. pg_stat_progress_create_index в качестве примера) улучшена внутренняя навигация за счет добавления ссылок на связанные элементы;
  • добавлены ресурсы внешние ссылки с дополнительной информацией;
  • теперь есть управление версиями, чтобы вы могли видеть, как Postgres эволюционировал от одной версии к другой.


AGE 0.4.0

Расширение, добавляющее графовую функциональность. Новшества в 0.4.0 здесь.

pg_log_statements 0.0.2

pg_log_statements расширение PostgreSQL, которое позволяет логировать SQL-запросы так, что переменная log_statement может быть установлена для отдельного серверного процесса (по id или фильтру), а не на уровне базы или инстанса.

Можно зайти на PGXN или на гитхабе создателя Пьера Форстмана, специалиста по Oracle.


Конференции


PostgresLondon 2021

Состоится уже 12-го мая, виртуальная. Расписание.

Highload++

Состоится офлайн 17 -18 мая в Крокус-Экспо, Москва. Расписание.

Postgres Vision 2020

Postgres Vision виртуальная конференция EDB, но участие свободное. Состоится 22-23 июня. Регистрация.

Следующий номер Postgresso 32 выйдет в первых числах июня.
Подробнее..

Ценность уместного комментария

01.03.2021 10:14:41 | Автор: admin

У каждого из нас есть задача, над решением которой ты долго и безуспешно бьешься, которую изучил уже и вдоль и поперек, но все равно не можешь получить нужный результат. При этом одни уверены, что твоя задача в принципе не имеет решения, другие - что проблемы вообще нет. Такой задачей для меня была длительность выполнения запросов к хранилищу данных на Greenplum. И как же приятно наконец-то написать, что я эту проблему победил!

Когда пытаешься понять, почему запросы занимают столько времениКогда пытаешься понять, почему запросы занимают столько времени

Из раза в раз при работе с хранилищем на ожидание результата запроса уходило по несколько минут. Причем не важно, запрос выбирает данные из таблицы на десять строк, или на миллион - время на ожидание будет соизмеримым.А любой простой в таком творческом процессе, как аналитика - это просто пытка!

Я много раз заходил на исправление такого поведения. Начал с тюнинга sql клиента. DBeaver предлагает пользователям целую кучу разных тонких настроек - кажется, я перепробовал их все, но успеха не достиг. Следом перепробовал настройки самого драйвера PostgreSQL - эффект тот же.

Все это время перед глазами был пример специализированного клиента для Greenplum - Aginity Workbench, в котором из коробки скорость выполнения аналогичных запросов ощутимо выше. Эта прога была дополнительным раздражающим фактором, так как найти причины такого ускорения у меня не получалось - ее исходный код закрыт и работает она только по лицензии, а подключение к greenplum в ней происходит при помощи нативных инструментов, а не обычных jdbc драйверов.

Озарение пришло, когда заглянул в системную вьюху pg_stat_activity - оказалось, что от клиента к базе в действительности летит не один запрос на данные, а два: сначала происходит выборка данных по запросу, а затем - чтение метаданных для этой выборки из pg_catalog. Причем из общего времени выполнения большую часть занимает именно чтение метаданных.

В этот момент я испытал целую бурю эмоций - от радости, что наконец-то нашел проблему, до недоумения от самой сути находки. То, что каталог прилично нагружен, я знал и раньше: к хранилищу сейчас подключено уже больше 250 систем-источников, в каждом не одна сотня таблиц, а в самих таблицах может быть двухуровневое партиционирование. Greenplum учитывает каждую партицию как отдельный объект, поэтому системные представления вроде pg_class прилично раздуваются. Но неужели действительно нужно обращаться к каталогу при любом запросе данных?

К счастью, драйвер постгреса имеет открытый исходный код, поэтому можно самостоятельно посмотреть, что же происходит под капотом. Заглянул в код, нашел нужный класс PgResultSetMetaData и его метод, который запрашивает метаданные - fetchFieldMetaData. Содержимое обнадеживает - похоже, без метаданных можно обойтись: fetchFieldMetaData вызывается из нескольких других методов, которые для моих целей не так важны, при этом сами эти методы допускают возврат пустого объекта, что намекает на возможность выпилить из кода вообще все обращения к fetchFieldMetaData, а значит избежать медленного запроса к каталогу.

Подробнее про методы:
  • isAutoIncrement. От запроса метаданных в этом методе легче всего отказаться: в нашем хранилище таких полей нет, да и комментарий "It is believed that PostgreSQL does not support this feature" как бы намекает, что и для других баз он не пригодится.

      public boolean isAutoIncrement(int column) throws SQLException {    fetchFieldMetaData();    Field field = getField(column);    FieldMetadata metadata = field.getMetadata();    return metadata != null && metadata.autoIncrement;  }
    
  • isNullable. При отсутствии метаданных в резалтсете все поля будут считаться nullable - не велика потеря.

      public int isNullable(int column) throws SQLException {    fetchFieldMetaData();    Field field = getField(column);    FieldMetadata metadata = field.getMetadata();    return metadata == null ? ResultSetMetaData.columnNullable : metadata.nullable;  }
    
  • getBaseColumnName. В коде драйвера этот метод используется в updatable резалтсетах при обновлении значений. В мои планы не входит использование этого функционала, но на всякий случай можно будет прикрутить выбрасывание исключений при вызове таких методов.

    public String getBaseColumnName(int column) throws SQLException {    Field field = getField(column);    if (field.getTableOid() == 0) {      return "";    }    fetchFieldMetaData();    FieldMetadata metadata = field.getMetadata();    return metadata == null ? "" : metadata.columnName;  }
    
  • getBaseSchemaName и getBaseTableName. Возвращают название схемы/таблицы, в которой находится запрошенный атрибут. В коде драйвера метод нигде не используется, мне эти сведения тоже не особо нужны.

    public String getBaseSchemaName(int column) throws SQLException {    fetchFieldMetaData();    Field field = getField(column);    FieldMetadata metadata = field.getMetadata();    return metadata == null ? "" : metadata.schemaName;  }public String getBaseTableName(int column) throws SQLException {    fetchFieldMetaData();    Field field = getField(column);    FieldMetadata metadata = field.getMetadata();    return metadata == null ? "" : metadata.tableName;  }
    

Проверяю влияние по коду, комментирую вызов метода fetchFieldMetaData, собираю jar файл драйвера, подсоединяюсь с его помощью к базе, иииии

Сказать, что это дало результат - это не сказать ничего. Запросы теперь просто летают. Ускорение - в разы. Отправил коллегам на тест - отзывы примерно такие:

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

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

P.S. В итоговой версии кода создал новый параметр подключения драйвера runtimeMetaDisable. Вызов метаданных и выбрасывание исключений привязал к его значению. Такой подход более гибок, чем жестко закомментированный вызов метода и позволяет управлять поведением драйвера в зависимости от потребностей. Код выложил на гитхаб. Если у вашей базы тяжелый каталог и вы хотите попробовать драйвер в деле, но не знакомы с миром java и не знаете, как собрать jar файл драйвера - напишите в комментариях!

Подробнее..

OpenGauss новая СУБД от Huawei для нагруженных enterprise-проектов прибавила в функциональности

05.11.2020 12:07:06 | Автор: admin
openGauss система управления реляционными базами данных с открытым исходным кодом, созданная инженерами Huawei. Новая версия 1.0.1, которая стала доступна в октябре 2020 года, значительно расширяет возможности СУБД и делает ее перспективным выбором для целого ряда IT-задач, прежде всего в крупных корпоративных проектах.



Ядро openGauss построено на основе объектно-реляционной системы управления базами данных PostgreSQL. Его функциональность была усовершенствована в расчете на решение задач уровня предприятия.

Концептуально openGauss представляет собой многоцелевую БД: строчное хранение в ней позволяет поддерживать сервисы с интенсивным обновлением данных, колоночное хранение ускоряет выполнение аналитических задач, а in-memory engine повышает пропускную способность при решении задач, чувствительных ко времени отклика. Развертывается решение как в контейнерах, так и на физических серверах с процессорами x86-64 или Kunpeng разработки Huawei.

Официальный запуск первой версии openGauss состоялся 1 июля 2020 года. А уже в середине осени был произведен релиз 1.0.1, в который включено более двадцати доработок.

В текущем исполнении openGauss обладает широким набором примечательных возможностей. Прежде всего это поддержка многоядерной архитектуры с управляемым параллелизмом. Надо отметить также интеллектуальную настройку параметров, диагностику медленных SQL, многомерный самоконтроль производительности и онлайн-прогнозирование выполнения SQL, значительно упрощающее O&M.

Достойны упоминания показатели быстродействия openGauss. В частности, система осуществляет до 1,5 млн tpmC на двух 64-ядерных процессорах Kunpeng, а переключение при сбое узла занимает у нее менее 10 с.

Коротко обозначим функции openGauss, определяющие ее преимущества.

  • Высокая готовность. Функции журналирования WALs (write-ahead logs) обеспечивают возможности горячего резервного копирования и восстановления. Утилита gs_basebackup позволяет сделать полную резервную копию БД, в том числе сжатую. В мире PostgreSQL вопрос инкрементального резервного копирования остается открытым, поэтому компаниям приходится самостоятельно решать эту задачу в каждом конкретном случае. Новая версия 1.0.1 поддерживает функциональность инкрементального резервного копирования при включении параметра GUC enable_cbm_tracking (и далее база данных будет отслеживать изменение страниц данных).

    Катастрофоустойчивость openGauss решается за счет организации Standby на удаленной площадке, причем синхронизация данных возможна в синхронном и асинхронном режиме. Текущий релиз СУБД поддерживает до четырех реплик на физическом уровне.
  • Высокая производительность. В openGauss таблицу, включая ее индексы, можно целиком поместить в память. Это возможно благодаря Memory-Optimized Tables (MOT) высокопроизводительному OLTP-движку для обработки данных в памяти. MOT поддерживает работу с таблицами в строчном формате, при этом доступна вся функциональность openGauss, включая транзакции и отказоустойчивость.

    Особенности реализации MOT и результаты его тестирования на производительность TPC-C приведены в отдельном документе.



    Необходимо также упомянуть возможность создания Materialized View срез данных с предварительно рассчитанными показателями (агрегатами) хранится на уровне таблиц БД, существенно ускоряя выполнение аналитических задач.
  • Управляемость серьезно улучшена за счет автоматических отчетов производительности (WDR). Чтобы задействовать эту функцию, достаточно установить параметр enable_wdr_snapshot=on и указать количество дней хранения для параметра wdr_snapshot_retention_days. Далее ядро базы данных будет автоматически сохранять снимки с метриками производительности, в том числе и медленные SQL. WDR позволяет формировать отчеты о производительности между указанными периодами времени (snapshots) в формате HTML или PDF.
  • Гибкость. Интеграция с внешними источниками данных реализована через Foreign Data Wrappers (FDW). В актуальном релизе поддерживается интеграция с Oracle, MySQL, openGauss.

    Отдельного внимания заслуживает Global Temporary Tables (GTT). Сам объект создается в БД один раз, далее GTT используется многократно для хранения промежуточных результатов транзакций или сессии. Данные во временной таблице видны только для текущей сессии независимо от фиксации транзакции. Данные теряются после отключения-завершения сессии. Это незаменимая функциональность для ETL или систем отчетности.


На openGauss распространяется действие лицензии Mulan PSL v2, что дает разработчикам возможность свободно изменять код СУБД, использовать его и ссылаться на него. Исходный программный код проекта полностью доступен в его репозитории.

Напомним, Huawei платиновый партнер разработчиков ПО с открытым кодом Linux, Apache и Openstack, а также стратегический член Eclipse Foundation. Мы активно участвуем в проектах по созданию Open Source решений, в том числе:

  • Linux-дистрибутива openEuler;
  • фреймворка для задач deep learning MindSpore;
  • интеллектуальной платформы для обеспечения автономности открытых данных SODA;
  • формата хранения больших данных Apache CarbonData;
  • платформы микросервисов Apache ServiceComb;
  • фреймворка для граничных вычислений CNCF KubeEdge;
  • высокопроизводительной системы управления batch-процессами CNCF Volcano.


Будем рады ответить на ваши вопросы в комментариях!
Подробнее..

Как синхронизировать сотни таблиц базы в Kafka, не написав ни одного продюсера

25.11.2020 14:11:26 | Автор: admin


Привет, Хабр! Меня зовут Сергей Бевзенко, я ведущий разработчик Delivery Club в команде Discovery. Наша команда занимается навигацией пользователя по приложению Delivery Club: мы отвечаем за основную выдачу ресторанов, поиск и всё, что с этим связано.

Я расскажу про Kafka Connect: что это такое, какова общая концепция и как работать с этим фреймворком. Это будет полезно тем, кто использует Kafka, но не знаком с Kafka Connect. Если у вас огромный монолит и вы хотите перейти на событийную модель, но сталкиваетесь со сложностью написания продюсеров, то вы тоже найдёте здесь ответы на свои вопросы. В комментариях можем сравнить ваш опыт использования Kafka Connect с нашим и обсудить любые вопросы, которые с этим связаны.

План


1. Предпосылки
2. Как используется Kafka Connect
2.1. Как запустить Kafka Connect
3. Запуск коннекторов
4. Настройка коннекторов
4.1. Причины выбора коннекторов
4.2. Jdbc и Debezium
4.3. Debezium Connector
4.4. JdbcSinkConnector
4.5. Трансформеры
5. Deploy
5.1. Deploy Kafka Connect Delivery Club
6. Что нам дало использование Kafka Connect

Предпосылки


Delivery Club не молодая компания. Она основана в сентябре 2009 года. Мы постоянно развиваемся и улучшаем наши сервисы, без этого рост невозможен.

У нас есть 10-летний Legacy-монолит. Он служит основой многих процессов. Да, новые сервисы мы, конечно же, пишем. Делаем это на Go, и иногда на PHP. Это два основных языка backend-разработки в Delivery Club. Также мы переходим на событийную модель с использованием шины событий: все изменения данных в системе это события, попадающие в шину, и любой сервис может подписаться на них.

Какие это события?


В компании есть множество интеграции с различными ресторанами, магазинами, аптеками и т.д. Также у нас есть служба логистики, которая работает с курьерами, их маршрутами, заказами, распределением. Есть и отличный отдел R&D, который занимается различными исследованиями и околонаучной разработкой. И, конечно, есть другие отделы. У каждого направления множество сервисов, и все они генерируют огромное количество событий. В качестве шины для них мы используем Apache Kafka. Но десятилетний Legacy никуда не делся. Внутри него множество админок, которые являются источниками данных. Без крайней нужды трогать их не рекомендуется.

Сервис Каталог


Как один из этапов развития, перед нашей командой стояла задача переписать основную выдачу приложения. За неё отвечал монолит, как и за большую часть функциональности. И наступил момент, когда вносить какие-либо изменения в эту функциональность стало невероятно долго.

В нашем случае всё началось с небольшой задачи: отображать в основной выдаче дополнительные ярлыки у ресторанов, в которых есть какие-то акции. Решений было несколько, но большинство из них сильно повышало нагрузку на базу и увеличивало время ответа. Но, надо признаться, выдача и так была не особо быстрой.

Единственным оптимальным решением было написать на Go новый сервис, который помог бы решить все проблемы, имевшиеся в монолите. К тому же мы смогли сильно (в три раза) сократить время ответа.

Но наш монолит является мастером данных для основной выдачи, и новый сервис должен иметь к ним доступ.

Как писать продюсеры в условиях 10-летнего Legacy


В самой первой версии Catalog MVP мы ходили в реплику монолита, чтобы быстро запуститься (для нас важен Time to market). Но оставлять так мы не хотели, поэтому нужно было денормализовать данные из монолита. А для этого необходимо начать продьюсить данные.

Есть несколько подходов:

  1. Переписать монолит. Тут вспоминаем все те статьи, доклады и книги о том, как переписывать монолит. Это сложный и долгий процесс. Он связан с большим количеством рисков. Конечно, мы выносим функциональность из монолита, но делаем это постепенно, аккуратно. Не в ущерб бизнесу.
  2. Писать свои продюсеры в монолите. Надо найти все места в коде, где происходит изменения в базе. В этих местах добавлять также отправку событий в шину. Если у вас хорошая архитектура монолита, с выделенным слоем репозитория, то сделать это лишь вопрос времени. Но Legacy не будет Legacy, если там всё хорошо с архитектурой. Так что этот вариант тоже очень сложен и трудозатратен.
  3. Использовать готовые решения для интеграции базы данных и Kafka. Можно использовать фреймворк Kafka Connect.

Kafka Connect


Как он используется


Чаще всего Kafka используют так:

Source => Kafka

Kafka => Kafka

Kafka => Storage

Kafka => App



То есть нам приходится писать собственные консьюмеры и продюсеры и решать однообразные задачи при их разработке:

  • Прописывать правила подключения к источникам.
  • Обрабатывать ошибки.
  • Прописывать правила ретраев.

Наиболее полно API Kafka поддерживается только в языках Java и Scala. В других языках поддержка не всегда полная. Поэтому разработчики Kafka предложили свои инструменты для решения таких задач: фреймворки Kafka Connect и Kafka Streams:

Source => Kafka (connect)

Kafka => Kafka (streams)

Kafka => Storage (connect)

Kafka => App



Когда говорят, что Kafka Connect поставляется вместе с Kafka, это не какая-то скрытая функциональность Kafka-брокеров. Это именно отдельное приложение, которое имеет настройки подключения к Kafka и источнику/приёмнику. Работу с Kafka Connect мы рассмотрим ниже.

Но сначала нужно ввести три важных термина:

  • worker инстанс/сервер Kafka Connect;
  • connector Java class + пользовательские настройки;
  • task один процесс connector'a.

Worker экземпляр Kafka Connect. Kafka Connect можно запускать в двух режимах: standalone и distributed, на нескольких нодах или виртуальных машинах. То есть можно просто запустить один worker или собрать кластер workerов. Рекомендуется использовать standalone-режим при локальной разработке, настройке и отладке коннекторов, а distributed в боевых условиях.

Преимущество distributed mode


Предположим, мы запустили четыре worker'а Kafka Connect и создали три connector'а с разным количеством task'ов.

  • Во-первых, Kafka Connect автоматически распределит таски коннекторов по разным воркерам.
  • Во-вторых, Kafka Connect отслеживает своё состояние в кластере. Если обнаружит, что один из воркеров недоступен, выполнит перебалансировку и перераспределит недоступные таски по работающим воркерам.

Какие ещё задачи решает Kafka Connect:

  • отказоустойчивость (fault tolerance);
  • принцип только один раз (exactly once);
  • распределение (distribution);
  • упорядочивание (ordering).



Как я говорил выше, фреймворк используется для передачи данных из источника в Kafka либо из Kafka в приёмник. В соответствии с этим коннекторы делятся на два вида:

  • Source Connectors;
  • Sink Connectors.



Коннекторов уже очень много написано. Например, на сайте confluent их сейчас 163, а на просторах интернета ещё больше.

Вы можете написать свой коннектор на Java и Scala. Для этого нужно создать подключаемый jar-файл, реализовав простой интерфейс коннектора.

Как запустить Kafka Connect


Локально


Поставляется вместе с Kafka

Идём на сайт Kafka и скачиваем нужную нам версию: http://kafka.apache.org/downloads.

Binary downloads:

  • Scala 2.12 - kafka_2.12-2.6.0.tgz (asc, sha512)
  • Scala 2.13 - kafka_2.13-2.6.0.tgz (asc, sha512)

Например, выберем версию Scala 2.12 (kafka_2.12-2.6.0.tgz). Распакуем архив и посмотрим в директорию kafka_2.12-2.6.0/bin. Там будут скрипты для запуска Apache Kafka (kafka-server-start.sh, kafka-server-stop.sh) и утилиты для работы с ней. Например, kafka-console-consumer.sh, kafka-console-producer.sh. А также там будут скрипты для запуска Kafka Connect (connect-distributed.sh, connect-standalone.sh), и многое другое.

Рекомендую зайти в директорию kafka_2.12-2.6.0/config там вы увидите настройки по умолчанию запуска и Kafka-брокера, и Kafka Connect.

  • connect-distributed.properties
  • connect-standalone.properties

Вот так выглядит конфигурация по умолчанию config/connect-distributed.properties:

bootstrap.servers=localhost:9092rest.port=8083group.id=connect-clusterkey.converter=org.apache.kafka.connect.json.JsonConvertervalue.converter=org.apache.kafka.connect.json.JsonConverterkey.converter.schemas.enable=truevalue.converter.schemas.enable=trueinternal.key.converter=org.apache.kafka.connect.json.JsonConverterinternal.value.converter=org.apache.kafka.connect.json.JsonConverterinternal.key.converter.schemas.enable=falseinternal.value.converter.schemas.enable=falseoffset.storage.topic=connect-offsetsconfig.storage.topic=connect-configsstatus.storage.topic=connect-statusoffset.flush.interval.ms=10000plugin.path=/opt/kafka/plugins

Kafka Connect можно запускать в режиме standalone. Это удобно для локальной разработки и тестирования, но в боевых условиях рекомендуется использовать connect-distributed (причины были описаны выше).

Режим standalone чаще всего используется для локальной разработке и тестирования.

Чтобы запустить Kafka Connect, выполните команду:

cd kafka_2.12-2.6.0bin/connect-standalone.sh config/connect-standalone.properties

Docker

Во многих Docker-образах используется этот же подход, поэтому вам достаточно переопределить CMD в Dockerfile, чтобы получить образ с Kafka Connect.

Например:

CMD ["bin/connect-distributed.sh", "cfg/connect-distributed.properties"]

Конечно, есть и готовые образы. Я рекомендую использовать варианты от компании Confluent:


Запуск коннекторов


После того, как вы запустите Kafka Connect, вы можете запускать на нём свои коннекторы.

Для управления Kafka Connect используется REST API. Полную документацию по нему можно посмотреть на сайте. Я опишу лишь те методы, которые нам понадобятся для демонстрации работы Kafka Connect.

Запросим список классов коннекторов, которые добавлены в ваш Kafka Connect:

curl -X GET "${KAFKA_CONNECT_HOST}/connector-plugins" -H "Content-Type: application/json"

В ответ мы получим нечто подобное:

HTTP/1.1 200 OK

[    {        "class": "io.debezium.connector.mysql.MySqlConnector"    },    {        "class": "io.confluent.connect.jdbc.JdbcSinkConnector"    }]

То есть вы можете создавать коннекторы только этих классов. Если хотите добавить новый класс, нужно скачать jar этого коннектора и добавить в директорию plugin.path из настройки Kafka Connect. См. файл connect-distributed.properties.

Запросим список запущенных коннекторов:

curl -X GET "${KAFKA_CONNECT_HOST}/connectors" -H "Content-Type: application/json"

В ответ получим:

HTTP/1.1 200 OK

Content-Type: application/json ["my-source-debezium", "my-sink-jdbc"]

Видим, что у нас создано два коннектора с именами my-source-debezium и my-sink-jdbc.

Получение информации о запущенном коннекторе

Общая информация:

curl -X GET "${KAFKA_CONNECT_HOST}/connectors/my-sink-jdbc" -H "Content-Type: application/json"

Конфигурация запущенного коннектора (config):

curl -X GET "${KAFKA_CONNECT_HOST}/connectors/my-sink-jdbc/config" -H "Content-Type: application/json"

Состояние запущенного коннектора (status):

curl -X GET "${KAFKA_CONNECT_HOST}/connectors/my-sink-jdbc/status" -H "Content-Type: application/json"

Создание коннектора


Пример:

curl -X POST "${KAFKA_CONNECT_HOST}/connectors" -H "Content-Type: application/json" -d '{ \    "name": "my-new-connector", \    "config": { \      "connector.class": "io.confluent.connect.jdbc.JdbcSinkConnector", \      "tasks.max": 1,      "topics": "mysql-table01,mysql-table02", \      "connection.url": "jdbc:postgresql://postgres:5432/catalog", \      "connection.user": "postgres", \      "connection.password": "postgres", \      "auto.create": "true" \    } \  }'

То есть необходимо методом POST отправить конфигурацию коннектора.

Обратите внимание, что имя коннектора должно быть уникальным в вашем кластере Kafka Connect. Но вы можете создавать несколько коннекторов одного класса с разными настройками.

Также у любого коннектора есть три обязательных параметра:

  • name уникальное имя;
  • connector.class класс коннектора;
  • tasks.max максимальное количество потоков, в которых может работать коннектор.

Настройка коннекторов


Я хотел бы рассказать про настройку коннекторов на примере DebeziumMysqlConnector и JdbcSinkConnector. С этих классов мы в Delivery Club начали работу. Но сначала я расскажу, почему вы выбрали именно их.

Причины выбора коннекторов


Как я рассказывал, мы выносили функциональность из нашего монолита. Сделали новый сервис Каталог, который отвечает за основную выдачу ресторанов.

Но для этой функциональности были необходимы данные, мастером которых был монолит. Эти данные ещё не отправлялись в шину событий.

Для MVP Каталога решили использовать Shared Database. То есть наш новый сервис обращался в базу монолита.



Таким образом мы сняли нагрузку с монолита, но нагрузка на старую базу осталась. После создания MVP нужно закрыть технический долг и отказаться от этого антипаттерна.



Две главные задачи, которые мы решали:

  • переход на событийную модель (первый этап);
  • разгрузка базы данных.

Jdbc и Debezium


Когда ищешь коннекторы для баз данных, первое, что находишь JdbcSourceConnector и JdbcSinkConnector.

Нам отлично подходит JdbcSinkConnector в качестве sink-коннектора. Он подписывается на топик Kafka и выполняет запросы на добавление, изменение и удаление данных в базе.

Но в качестве Source-коннектора он нам не подходит, так как делает SQL-запросы в базу по таймеру, а это создает ещё большую нагрузку на базу-источник. Мы как раз хотим от этого уйти.

Но нам подходит DebeziumMysqlConnector. Он делает одну классную вещь: подключается к MySQL-кластеру как обычная MySQL-реплика и умеет читать бинлог. Таким образом, мы не создаём дополнительную нагрузку на базу (за исключением встроенных механизмов MySQL-репликации).



Помимо этого, у Debezium-коннектора есть ещё одно преимущество перед Jdbc. Так как Debezium отслеживает бинлог, он может определять моменты удаления записей в базе данных. У Jdbc нет такой возможности, так как он берёт текущее состояние базы и ничего не знает о предыдущем состоянии.

Debezium Connector




Все настройки коннектора можно посмотреть на сайте.

Давайте рассмотрим настройки коннектора и обсудим выбор некоторых параметров.

Файл debezium-config.json:

{  "name": "my-debezium-mysql-connector",  "config": {    "tasks.msx": 1,    "connector.class": "io.debezium.connector.mysql.MySqlConnector",    "database.hostname": "${MYSQL_HOST}",    "database.serverTimezone": "Europe/Moscow",    "database.port": "${MYSQL_PORT}",    "database.user": "${MYSQL_USER}",    "database.password": "${MYSQL_PASS}",    "database.server.id": "223355",    "database.server.name": "monolyth_db",    "table.whitelist": "${MYSQL_DB}.table_name1",    "database.history.kafka.bootstrap.servers": "${KAFKA_BROKER}",    "database.history.kafka.topic": "monolyth_db.debezium.history",    "database.history.skip.unparseable.ddl": true,    "snapshot.mode": "initial",    "time.precision.mode": "connect"  }}

Подключения к базе данных:

    "database.hostname": "${MYSQL_HOST}",    "database.serverTimezone": "Europe/Moscow",    "database.port": "${MYSQL_PORT}",    "database.user": "${MYSQL_USER}",    "database.password": "${MYSQL_PASS}",

Следует иметь в виду, что этот пользователь должен иметь права:

GRANT SELECT, RELOAD, SHOW DATABASES, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'user' IDENTIFIED BY 'password';

ID реплики, под которым будет зарегистрирован коннектор, и его имя сервера:

    "database.server.id": "223355",    "database.server.name": "monolyth_db",

Список таблиц для синхронизации:

"table.whitelist": "${MYSQL_DB}.table_name1,${MYSQL_DB}.table_name2",

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

Настройки создания snapshot'а:

    "database.history.kafka.bootstrap.servers": "${KAFKA_BROKER}",    "database.history.kafka.topic": "debezium.db.history",    "snapshot.mode": "initial",

Для чего нужен snapshot

Когда ваш коннектор Debezium MySQL запускается в первый раз, он выполняет начальный согласованный снимок вашей базы данных и сохраняет его в топик Kafka. Даже если вы будете отслеживать только несколько таблиц из базы, в database.history будет записана вся схема. Но можно не переживать из-за размера этого топика, он будет очень маленьким (менее 1 Мб).

Пропуск определений в снимке, которые по каким-то причинам не удалось распарсить:

    "database.history.skip.unparseable.ddl": true,

Эту опцию мы включили, потому что сталкивались с такими ошибками, когда определения в бинлоге использовали неверный синтаксис. Сервер MySQL более-менее интерпретирует эти инструкции и потому не падает. Но анализатор SQL-запросов в DebeziumConnector'е с ними не справляется и падает с ошибкой. Чтобы не падать, а игнорировать нечитаемые запросы, необходимо включить эту опцию.

Точность типа данных time:

"time.precision.mode": "connect",

Эта настройка уменьшает точность типа данных time с микросекунд до миллисекунд.

Описанную конфигурацию уже можно использовать для production-окружения. А в документации есть полный перечень настроек с подробным описанием.

Также нашу конфигурацию можно дополнить различными трансформерами по преобразованию данных и маршрута топиков. И один из важнейших трансформеров в проекте Debezium io.debezium.transforms.ExtractNewRecordState. Почитать подробнее о нём можно в документации. Если кратко: вам потребуется его использовать для преобразования формата Debezium в формат Jdbc.

В целом, все трансформации рекомендуется использовать на стороне Sink-коннектора, а Source-коннекторы должны отправлять данные в топик Kafka без изменений.

Создание Debezium MySqlConnector:


curl  -X POST ${KAFKA_CONNECT_HOST}/connectors -H "Content-Type: application/json" -d @debezium-config.json

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

Connector configuration is invalid and contains the following 1 error(s):
Configuration is not defined: database.history.connector.id
Configuration is not defined: database.history.connector.class
Unable to connect: Communications link failure


The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
You can also find the above list of errors at the endpoint `/connector-plugins/{connectorType}/config/validate````


Эта ошибка говорит о том, что у вас указаны некорректные параметры подключения к MySQL. Проверьте ваши логин/пароль, а также убедитесь, что у пользователя есть права на репликацию (см. выше).

После создания коннектора можно проверить его состояние. Этот метод также используется в качестве метрики.

curl  -X GET ${KAFKA_CONNECT_HOST}/connectors/my-debezium-mysql-connector/status

Мы увидим такой ответ:

{  "name": "my-debezium-mysql-connector",  "connector": {    "state": "RUNNING",    "worker_id": "connect:8080"  },  "tasks": [    {      "id": 0,      "state": "RUNNING",      "worker_id": "connect:8080"    }  ],  "type": "source"}

После того, как мы запустили source connector, можно убедиться, что топики были созданы и можно прочитать из них данные. Для работы с Kafka будем использовать удобную утилиту kafkacat.

Какие топики были созданы нашим коннектором:

kafkacat -b ${KAFKA_BROKER} -L | grep 'monolyth_db'

Чтение данных из топика monolyth_db.debezium.history:

kafkacat -b ${KAFKA_BROKER} -t monolyth_db.debezium.history -C -f 'Offset: %o\nKey: %k\nPayload: %s\n--\n'

Чтение данных из топика monolyth_db.table_name1 (${MYSQL_DB} имя вашей базы данных):

kafkacat -b ${KAFKA_BROKER} -t monolyth_db.${MYSQL_DB}.table_name1 -C -f 'Offset: %o\nKey: %k\nPayload: %s\n--\n'

В топиках вы увидите сообщения в формате avro (если вы использовали JsonSerializer для key, value серилизаторов). Вид и описание формата лучше прочитать в документации.

JdbcSinkConnector


В качестве Sink коннектора будем использовать JdbcSinkConnector.



Рассмотрим его конфигурацию

Создадим файл my-jdbc-sink-connector.json:

{  "name": "my-jdbc-sink-connector",  "config": {    "connector.class": "io.confluent.connect.jdbc.JdbcSinkConnector",    "tasks.max": "2",    "connection.url": "jdbc:postgresql://${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}",    "connection.user": "${POSTGRES_USER}",    "connection.password": "${POSTGRES_PASS}",    "topics": "monolyth_db.${MYSQL_DB}.table_name1,monolyth_db.${MYSQL_DB}.table_name2",    "pk.fields": "id",    "pk.mode": "record_key",    "auto.create": "false",    "auto.evolve": "false",    "insert.mode": "upsert",    "delete.enabled": "true",    "transforms": "route,unwrap,rename_field,ts_updated_at,only_fields",    "transforms.route.type": "org.apache.kafka.connect.transforms.RegexRouter",    "transforms.route.regex": "([^.]+)\\.([^.]+)\\.([^.]+)",    "transforms.route.replacement": "${PG_DB}.public.$3",    "transforms.unwrap.type": "io.debezium.transforms.ExtractNewRecordState",    "transforms.unwrap.drop.tombstones": "false",    "transforms.rename_field.type": "org.apache.kafka.connect.transforms.ReplaceField$Value",    "transforms.rename_field.renames": "isDeleted:is_deleted,isActive:is_active",    "transforms.ts_updated_at.type": "org.apache.kafka.connect.transforms.TimestampConverter$Value",    "transforms.ts_updated_at.target.type": "Timestamp",    "transforms.ts_updated_at.field": "updated_at",    "transforms.ts_updated_at.format": "yyyy-MM-dd'T'HH:mm:ssXXX",    "transforms.only_fields.type": "org.apache.kafka.connect.transforms.ReplaceField$Value",    "transforms.only_fields.whitelist": "id,title,url_tag,sort,hide,created_at,updated_at"  }}

Тут, конечно, три обязательных для любого коннектора параметра:

"name": "my-jdbc-sink-connector","connector.class": "io.confluent.connect.jdbc.JdbcSinkConnector","tasks.max": "2",

Настройки подключения:

"connection.url": "jdbc:postgresql://${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}","connection.user": "${POSTGRES_USER}","connection.password": "${POSTGRES_PASS}",

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

"topics": "monolyth_db.${MYSQL_DB}.table_name1,monolyth_db.${MYSQL_DB}.table_name2",

JdbcConnector использует один топик для одной таблицы. Сопоставление топика и таблицы происходит по имени. Для коррекции используется route-трансформер. О трансформерах поговорим чуть ниже.

Если вы указываете несколько топиков, то у них у всех должны быть одинаковые pk.fields.

Сообщения в Kafka имеют ключ, создаваемый на основании первичного ключа (Primary Key) таблицы. Какой именно PR в таблице, необходимо указать в параметрах pk.fields, чаще всего это просто id:

"pk.fields": "id","pk.mode": "record_key",

Ключ может быть составной. Например, для кросс-таблиц:

"pk.fields": "user_id,service_id",

Следующие параметры очень красноречивые. Мы отключаем автоматическое создание и удаление таблиц, и разрешаем удалять данные:

"auto.create": "false","auto.evolve": "false","insert.mode": "upsert","delete.enabled": "true",

Трансформеры


Последний блок настроек касается трансформеров.

"transforms": "route, unwrap, rename_field, ts_updated_at, only_fields",

Этот параметр указывает, какие трансформеры и в каком порядке выполнять. Они расположены в этой же конфигурации коннектора. Каждый трансформер имеет type (класс) и параметры.

Например, трансформер route отвечает за сопоставление имени топика и имени таблицы:

"transforms.route.type": "org.apache.kafka.connect.transforms.RegexRouter","transforms.route.regex": "([^.]+)\\.([^.]+)\\.([^.]+)","transforms.route.replacement": "${PG_DB}.public.$3",

Он используется в Debezium MySqlConnector: отправляет данные в Kafka топики с именами {server_name}.{database_name}.{table_name}, а JdbcSinkConnector принимает {database_name}.{schema_name}.{table_name}. Так как целевая база и таблица могут отличаться по именам (и у вас вряд ли имя базы будет public), то этот коннектор изменяет целевое имя топика.

Второй важный трансформер unwrap:

"transforms.unwrap.type": "io.debezium.transforms.ExtractNewRecordState","transforms.unwrap.drop.tombstones": "false",

Он преобразует формат Debezium в формат, с которым прекрасно работает JdbcSinkConnector.

Трансформеры rename_field, ts_updated_at и only_fields используются для переименования полей, преобразования дат и указания списка тех полей, которые необходимо синхронизировать. Так указывается конфигурация трансформера ts_updated_at:

"transforms.ts_updated_at.type": "org.apache.kafka.connect.transforms.TimestampConverter$Value","transforms.ts_updated_at.target.type": "Timestamp", "transforms.ts_updated_at.field": "updated_at", "transforms.ts_updated_at.format": "yyyy-MM-dd'T'HH:mm:ssXXX",

Deploy


В каждой компании деплой происходит по-разному: где-то используют Jenkins, где-то Gitlab CI или Bitbucket Pipelines, а кто-то пишет скрипты.

С Kafka Connect вы будете деплоить точно так же, как и в случае с другими сервисами в вашей компании.

Как я отмечал, Kafka Connect это отдельное stateless-приложение. Оно не зависит от Kafka-брокера и даже от версии Kafka. Если у вас уже есть Kafka старой версии, можно использовать новую версию Kafka Connect. Я рекомендую это и сделать. Например, мы использовали последнюю на тот момент версию Kafka Connect 2.5.0 с Kafka-брокером 0.10.х.

Поэтому нет каких-то общих советов и нюансов, как деплоить сервисы. Расскажу, как это происходит у нас.

Deploy Kafka Connect в Delivery Club


Kubernetes

Перед запуском в стейдж мы экспериментировали локально. Создавали свой Docker-образ на основе cp-kafka-connect, куда просто добавляли свои коннекторы.

Для стейджа было достаточно из этого образа собрать контейнер и выложить в Kubernetes, что мы и сделали.

Отмечу только, что 2 Гб памяти поду под Kafka Connect не хватает, и у нас поды по 4 Гб.

Production

На проде у нас внедрение совпало с внедрением нового кластера Kafka-брокеров. Мы приняли специфическое решение поднимать Kafka Connect на тех же серверах, где будут находиться Kafka-брокеры. Для этого использовали rpm-пакет от Confluent.

Сами настройки конфигов мы храним в репозитории. У нас есть несколько скриптов, которые позволяют управлять коннекторами: создавать, останавливать, перезапускать их.

Но это уже отдельная история как работать с Kafka Connect в проде, которая зависит от инфраструктуры компании.

Что нам дало использование Kafka Connect


Мы не стали писать множество продьюсеров в монолите для более чем 600 таблиц. По приблизительным подсчётам, это сэкономило нам более месяца работы пары разработчиков. И, конечно же, снизило возможность наделать множество ошибок в монолите. То есть мы избавились от потенциальных падений приложения.

Это позволило написать новый сервис выдачи ресторанов силами одной команды за один месяц.

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

Мы сняли нагрузку с самой нагруженной нашей части база данных монолита. Это примерно 150 RPS запросов к базе. И синхронизируем более 40 таблиц со скоростью 300 RPS.

Также мы разделил ответственность сервисов, что является первым шагов к разделению доменной области.

Резюме


Я очень рад, что вам удалось добраться до конца. В этой статье вы:

  • познакомились с общими принципами работы с Kafka Connect;
  • узнали, как запустить приложение Kafka Connect в разных режимах;
  • разобрались, как запускать и настраивать коннекторы для работы с базой и Kafka.

И я рад, что вас не испугал внушительный размер статьи, и рассчитываю, что вы будете обращать к ней в качестве примера работы с Kafka Connect и краткого справочника.
Подробнее..

Перевод Путеводитель по базам данных в 2021г

04.06.2021 20:14:20 | Автор: admin

Данные это один из наиболее важных компонентов геопространственных технологий и, пожалуй, любой другой отрасли. К управлению данными сейчас относятся серьезно во всех отраслях, поэтому знания по этой дисциплине имеют важное значение для карьеры ИТ-специалистов. Этот цикл статей задуман как универсальное руководство, в котором мы рассмотрим тему от и до, начиная с вопроса Что такое данные? и заканчивая изучением и применением геопространственных запросов.

Основные понятия баз данных

Что такое данные?

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

Что такое база данных?

Множество записей данных, собранных вместе, образуют базу данных. Базы данных обычно создаются для того, чтобы пользователи могли обращаться к большому количеству данных и массово выполнять с ними определенные операции.База данных может хранить что угодно: представьте себе, например, блокнот вашей бабушки со всеми ее вкусными рецептами, учетную книгу ваших родителей, куда они записывают все доходы и расходы, или свою страницу в Facebook со списком всех ваших друзей. Из этих примеров видно, что все данные в базе данных относятся более-менее к одному типу.

Зачем нужна база данных?

Создание базы данных упрощает разным пользователям доступ к наборам информации. Приведенные выше примеры показывают, что в базе данных мы можем хранить записи с информацией похожего типа, но это правда лишь отчасти, поскольку с появлением баз данных NoSQL это определение меняется (подробнее читайте далее в статье).Так как размер веб-сайтов становится все больше и степень их интерактивности все выше, данные о пользователях, клиентах, заказах и т.д. становятся важными активами компаний, которые испытывают потребность в надежной и масштабируемой базе данных и инженерах, способных в ней разобраться.

Система управления базами данных (СУБД)

Итак, мы уже знаем, что данные и базы данных важны, но как осуществляется работа с базами данных в компьютерных системах? Вот тут на сцену и выходит СУБД. СУБД это программное обеспечение, предоставляющее нам способ взаимодействия с базами данных на компьютере для выполнения различных операций, таких как создание, редактирование, вставка данных и т.д. Для этого СУБД предоставляет нам соответствующие API. Редко какие программы не используют СУБД для работы с данными, хранящимися на диске.Помимо операций с данными СУБД также берет на себя резервное копирование, проверку допуска, проверку состояния базы данных и т.д. Поэтому рекомендуется всегда использовать СУБД при работе с базами данных.

Пространственные данные и база данных

Особое внимание мы уделим обработке пространственных данных, поэтому я хотел бы обсудить здесь этот тип данных. Пространственные данные несколько отличаются от остальных. Координаты необходимо сохранять в особом формате, который обычно указан в документации на веб-сайте о базе данных. Этот формат позволяет базе считывать и правильно воспринимать координаты. Если обычно для поиска данных мы используем запросы типа Получить все результаты, где возраст>15, то пространственный запрос выглядит как-то так: Получить все результаты в радиусе 10км от определенной точки.Поэтому пространственные данные необходимо хранить в надлежащем формате.

Типы баз данных

Базы данных обычно делятся на два типа: реляционные и нереляционные. Оба типа имеют свои плюсы и минусы. Было бы глупо утверждать, что один лучше другого, поскольку это будет зависеть от варианта использования. Конкретно для пространственных данных я в 99% случаев использую реляционные базы данных, и вы скоро поймете почему.

Реляционные базы данных и РСУБД

Допустим, ваш начальник просит вас создать электронную таблицу с важной информацией, включающей имена, местонахождения, адреса электронной почты, номера телефонов и должности всех сотрудников. Вы сразу же откроете таблицу Excel или Google Spreadsheets, напишете все эти названия столбцов и начнете собирать информацию.

Образец таблицы с информациейОбразец таблицы с информацией

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

Связь между двумя столбцамиСвязь между двумя столбцами

Взаимосвязи в реляционных базах данных мы подробно рассмотрим позже.

По сравнению с базами данных NoSQL, недостатком реляционных баз данных является относительно медленное получение результатов, когда количество данных стремительно увеличивается (по мнению автора статьи прим. пер.). Еще один недостаток заключается в том, что при добавлении каждой записи нужно следовать определенным правилам (типы столбцов, количество столбцов и т.д.), мы не можем просто добавить отдельный столбец только для одной записи.В реляционных базах данных используется SQL(Structured Query Language язык структурированных запросов), с помощью которого пользователи могут взаимодействовать с данными, хранящимися в таблицах. SQL стал одним из наиболее широко используемых языков для этой цели. Мы подробнее поговорим об SQL чуть позже.Вот примеры некоторых известных и часто используемых реляционных баз данных: PostgreSQL, MySQL, MSSQL и т.д. У каждой крупной компании, занимающейся реляционными базами данных, есть собственная версия SQL. В большинстве аспектов они выглядят одинаково, но иногда требуется немного изменить какой-нибудь запрос, чтобы получить те же результаты в другой базе данных (например, при переходе из PostgreSQL в MySQL).

Нереляционные базы данных (NoSQL)

Все базы данных, не являющиеся реляционными, относятся к категории нереляционных баз данных. Обычно данные хранятся в нетабличном формате, например:

  1. Пара ключ-значение

  2. Формат JSON, XML

  3. Графовый формат

Основное преимущество баз данных NoSQL состоит в том, что все строки независимы и могут иметь разные столбцы. Как показано на изображении ниже, оба пользователя относятся к одной и той же таблице Core_user, но их записи содержат разную информацию.

База данных NoSQL реального времени в Google FirebaseБаза данных NoSQL реального времени в Google Firebase

База данных NoSQL реального времени в Google Firebase

При использовании баз данных NoSQL пользователям иногда приходится прописывать собственную логику, чтобы добавить уникальный ключ к каждой записи и тем самым обеспечить доступ к записям. В большинстве стандартных баз данных NoSQL, таких как Firebase и MongoDB, для хранения данных используется формат JSON. Благодаря этому очень легко и удобно выполнять операции с данными из веб-приложений, используя JavaScript, Python, Ruby и т.д.

Рекомендации по выбору типа базы для хранения пространственных данных

Очевидно, что нам хотелось бы сохранить точку, линию, многоугольник, растры и т.д. так, чтобы это имело смысл, вместо того чтобы сохранять просто координаты. Нам нужна СУБД, которая позволяет не только сохранять данные, но и запрашивать их пространственными методами (буфер, пересечение, вычисление расстояния и т.д.). На сегодняшний день для этого лучше всего подходят реляционные базы данных, поскольку в SQL есть функции, помогающие выполнять подобные операции. Использование таких дополнительных средств, как PostGIS для PostgreSQL, открывает разработчикам возможности для написания сложных пространственных запросов. С другой стороны, NoSQL тоже работает в области геопространственных технологий: например, MongoDB предоставляет кое-какие функции для выполнения геопространственных операций. Однако реляционные базы данных все же лидируют на рынке с большим отрывом.

Работа с РСУБД

Основное внимание мы уделим РСУБД, так как именно эти системы в большинстве случаев мы будем использовать для хранения пространственных данных и работы с ними. В качестве примера мы будем использовать PostgreSQL, поскольку это самая перспективная реляционная база данных с открытым исходным кодом, а ее расширение PostGIS позволяет работать и с пространственными данными. Вы можете установить PostgreSQL, следуя инструкциям из документации. Помимо PostgreSQL рекомендуется также загрузить и установить pgAdmin. Платформа pgAdmin предоставляет веб-интерфейс для взаимодействия с базой данных. Также для этого можно загрузить и установить какое-либо другое совместимое ПО или использовать командную строку.

pgAdmin4 на MacpgAdmin4 на Mac

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

Создание базы данных. Нам нужно создать базу данных (в идеале должно быть по одной базе данных для каждого проекта).

Создание новой базы данных для проектаСоздание новой базы данных для проекта

В инструменте запросов (Query Tool) база данных создается следующим образом:

CREATE DATABASE <database_name>

Создание таблиц. Создание таблицы требует некоторых дополнительных соображений, поскольку именно здесь нам нужно определить все столбцы и типы данных в них. Все типы данных, которые можно использовать в PostgreSQL, вы найдете здесь.

pgAdmin позволяет нам выбрать в таблице различные ключи и ограничения, например Not Null (запрет на отсутствующие значения), Primary Key (первичный ключ) и т.д. Обсудим это подробнее чуть позже.

Создание таблицы пользователейСоздание таблицы пользователей

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

CREATE TABLE <table_name> (<column_1> <datatype>,<column_2> <datatype>,.....<column_n> <datatype>PRIMARY KEY (<column>));

CRUD-операции с данными в таблицах

CRUD-операции (создание, чтение, обновление и удаление Create, Retrieve, Update, Delete) это своего рода hello world в мире СУБД. Поскольку эти операции используются наиболее часто, команды для их выполнения одинаковы во всех РСУБД. Мы будем писать и выполнять запросы в инструменте запросов в pgAdmin, который вызывается следующим образом:

Инструмент запросов (Query Tool) в pgAdminИнструмент запросов (Query Tool) в pgAdmin

1. Создание новой записи

Для добавления новой записи в таблицу используйте следующую команду:

INSERT INTO <tablename> (column1, column2, column3,...) VALUES (value1, value2, value3,...);

INSERT, INTO, VALUE являются ключевыми словами в SQL, поэтому их нельзя использовать в качестве переменных, значений и т.д. Чтобы добавить новую запись в нашу таблицу пользователей, мы напишем в инструменте запросов следующий запрос:

INSERT INTO users(name, employed, address) VALUES ('Sheldon Cooper', true, 'Pasadena');

Обратите внимание: строки всегда следует заключать в'' (одинарные кавычки), а не в"" (двойные кавычки).

2. Получение записей (всех или нескольких)

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

select <column1, column2 ,...> from <tablename> 

Этот код извлекает весь набор данных. Если вы хотите получить только 20записей, напишите:

select <column1, column2 ,...> from <tablename> limit 20

Если вы хотите получить данные из всех столбцов, то вместо перечисления названий всех столбцов можно написать:

select * from <tablename>

Если вы хотите получить результат с определенным условием, используйте ключевое слово WHERE, как показано ниже:

select * from <tablename> where <key> = <value>

Вы можете создавать даже сложные запросы, о которых мы поговорим позже.В нашем примере мы можем получить нужные нам данные:

--Retrieving Specific columns for all usersselect name,employed from users--Retrieving all columns for all usersselect * from users--Retrieving all columns for first 3 usersselect * from users limit 3--Retrieving all columns for all users where employed = trueselect * from users where employed = true

3. Обновление записей (всех или нескольких)РСУБД позволяет нам обновить все или только некоторые записи данных, указав новые значения для столбцов.

UPDATE <tablename> SET <column1> = <value1>, <column2> = <value2> 

Если вы хотите обновить определенные строки, добавьте условия с использованием ключевого слова WHERE:

UPDATE <tablename> SET <column1> = <value1>, <column2> = <value2>WHERE <column> = <value> 

В нашем случае мы обновим таблицы с помощью следующих запросов:

-- Make all rows as  employed = trueupdate users set employed = true-- change employed = false for entries with address = 'nebraska'update users set employed = false where address = 'nebraska'
Обновление записейОбновление записей

4. Удаление записей (всех или нескольких)Удалять записи в SQL легко. Пользователь может удалить либо все строки, либо только определенные строки, добавив условие WHERE.

-- Deleting all entries Delete from <tablename> -- Deleting entries based on conditionsDelete from <tablename> where <column> = <value> 
-- Deleting all entries Delete from users-- Deleting entries based on conditionsDelete from users where employed = false
Удаление записей из таблицыУдаление записей из таблицы

CRUD-операции используются очень часто, поскольку выполняют основные функции в базе данных.


Перевод подготовлен в рамках курса Базы данных. Все желающих приглашаем на бесплатный двухдневный онлайн-интенсив Бэкапы и репликация PostgreSQL. Практика применения. Цели занятия: настроить бэкапы; восстановить информацию после сбоя. Регистрация здесь.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru