Обновить
-15
-24.1
Ринат@pg_expecto

PostgreSQL Performance Engineer

Отправить сообщение

А я еще полгода назад, когда только началось массовое использование сказал - "В области генерации тестов и семантического анализа текстов - человек в принципе не способен конкурировать с алгоритмами". Да это и не нужно.

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

В профессиональной области - реальные примеры использования нейросетей:

1)можно вручную смотреть html отчеты , а можно использовать нейросеть которая даст анализ и выделит ключевые различия.

2)можно вручную пытаться найти одинаковые паттерны в текстах сотен SQL запросов. А можно использовать нейросеть и получить ответ меньше чем за минуту.

3)можно вручную анализировать причины ожиданий. А можно использовать нейросеть и получить быстрый анализ необходимых действий для оптимизации ожиданий СУБД.

Так, что забавно наблюдать истерику граничащую с паранойей - "спасите помогите ИИ" , "Эта статья плохая , ее ИИ сгенерил я ее читать не буду" :-)

Каждому молотку - свой гвоздь.

Многие вещи можно делать намного проще через таблицы и хранимые процедуры. Но это типа антипаттерн сегодня

Да, был долгий срач на Хабре на эту тему. По личному опыту участия в разработке - причина переноса бизнес логики с уровня СУБД на уровень приложения только одна - нет на рынке разработчиков СУБД.. Или уже нет, или почти нет. Опять таки по лично опыту - искали полгода, а время идет. Кончилось тем , что перешли на ОРМ и я ушел из проекта.

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

Стиль и принцип это основа нормальной разработки, не важно на уровне сервера или backend или фронтенда. Если бардак и авось, да будет больно - "ой у нас тут что-то все тормозит. А что вы хотели - у вас backend передает на выполнение запрос стоимостью 3 триллиона".

Интересно , почему в другом случае, использование array не привело к снижению стоимости плана

SELECT c использованием max
SELECT flight_id, max(boarding_time) AS max_boarding_time
FROM bookings.boarding_passes
GROUP BY flight_id ;
SELECT c использованием array
SELECT flight_id, (ARRAY_AGG(boarding_time ORDER BY boarding_time DESC))[1] AS max_boarding_time
FROM bookings.boarding_passes
GROUP BY flight_id;
Тестовая таблица
demo=#  \d bookings.boarding_passes

                 Unlogged table "bookings.boarding_passes"

    Column     |           Type           | Collation | Nullable | Default
---------------+--------------------------+-----------+----------+---------
 ticket_no     | text                     |           | not null |
 flight_id     | integer                  |           | not null |
 seat_no       | text                     |           | not null |
 boarding_no   | integer                  |           |          |
 boarding_time | timestamp with time zone |           |          |

Indexes:
    "boarding_passes_pkey" PRIMARY KEY, btree (ticket_no, flight_id)
    "boarding_passes_flight_id_boarding_no_key" UNIQUE CONSTRAINT, btree (flight_id, boarding_no)
    "boarding_passes_flight_id_boarding_time" btree (flight_id, boarding_time)
    "boarding_passes_flight_id_seat_no_key" UNIQUE CONSTRAINT, btree (flight_id, seat_no)

Foreign-key constraints:
    "boarding_passes_ticket_no_flight_id_fkey" FOREIGN KEY (ticket_no, flight_id) REFERENCES segments(ticket_no, flight_id)
demo=# select * from pg_stat_all_tables where relname ='boarding_passes'\gx

-[ RECORD 1 ]-------+------------------------------
relid               | 8169623
schemaname          | bookings
relname             | boarding_passes
seq_scan            | 51900
last_seq_scan       | 2025-11-27 07:19:15.316786+00
seq_tup_read        | 205297812833
idx_scan            | 82596508
last_idx_scan       | 2025-11-27 07:25:39.118427+00
idx_tup_fetch       | 2946656229
n_tup_ins           | 19870560
n_tup_upd           | 19831846
n_tup_del           | 0
n_tup_hot_upd       | 0
n_tup_newpage_upd   | 6267745
n_live_tup          | 19870557
n_dead_tup          | 0
n_mod_since_analyze | 0
n_ins_since_vacuum  | 0
last_vacuum         | 2025-11-27 05:00:10.432594+00
last_autovacuum     | 2025-11-17 13:09:35.118797+00
last_analyze        | 2025-11-27 05:00:26.488626+00
last_autoanalyze    | 2025-11-17 13:09:49.000099+00
vacuum_count        | 114
autovacuum_count    | 32
analyze_count       | 115
autoanalyze_count   | 14
EXPLAIN ANALYZE с использованием max
                                                                       QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------
Finalize HashAggregate  (cost=287737.64..288590.98 rows=85335 width=12) (actual time=1947.406..1971.006 rows=97461 loops=1)
   Group Key: flight_id
   Batches: 1  Memory Usage: 9233kB
   ->  Gather  (cost=251043.59..286030.94 rows=341340 width=12) (actual time=1681.508..1765.893 rows=433513 loops=1)
         Workers Planned: 4
         Workers Launched: 4
         ->  Partial HashAggregate  (cost=250043.59..250896.94 rows=85335 width=12) (actual time=1670.910..1700.935 rows=86703 loops=5)
               Group Key: flight_id
               Batches: 1  Memory Usage: 8721kB
               Worker 0:  Batches: 1  Memory Usage: 8721kB
               Worker 1:  Batches: 1  Memory Usage: 8721kB
               Worker 2:  Batches: 1  Memory Usage: 8721kB
               Worker 3:  Batches: 1  Memory Usage: 8721kB
               ->  Parallel Seq Scan on boarding_passes  (cost=0.00..225205.39 rows=4967639 width=12) (actual time=0.044..610.620 rows=3974111 loops=5)
Planning Time: 0.208 ms
Execution Time: 1980.245 ms
(16 rows)
EXPLAIN ANALYZE с использованием array
                                                                                           QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
GroupAggregate  (cost=18.77..1904463.85 rows=85335 width=12) (actual time=1.471..16508.645 rows=97461 loops=1)
   Group Key: flight_id
   ->  Incremental Sort  (cost=18.77..1804044.39 rows=19870556 width=12) (actual time=1.111..12789.624 rows=19870557 loops=1)
         Sort Key: flight_id, boarding_time DESC
         Presorted Key: flight_id
         Full-sort Groups: 93168  Sort Method: quicksort  Average Memory: 27kB  Peak Memory: 27kB
         Pre-sorted Groups: 91575  Sort Method: quicksort  Average Memory: 37kB  Peak Memory: 37kB
         ->  Index Only Scan using boarding_passes_flight_id_boarding_time on boarding_passes  (cost=0.56..382097.80 rows=19870556 width=12) (actual time=0.788..3785.574 rows=19870557 loops=1)
               Heap Fetches: 0
Planning Time: 0.202 ms
Execution Time: 16516.294 ms
(11 rows)

C использованием max: Finalize HashAggregate  (cost=287737.64..288590.98 )

C использованием array: GroupAggregate  (cost=18.77..1904463.85 )

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

Вопрос - что значить "большое количество" ? Большое это сколько ? 1000 больше чем 10 на 2 порядка . Но удастся ли в принципе набрать 1000 кейсов например по проблемам оптимизации производительности СУБД ?

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

подход, связанный как раз с цепочками рассуждений

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

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

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

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

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

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

Метод научного тыка ;-)

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

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

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

Если очень упрощенно, стандартный сценарий:

———

  1. Вопрос: В тесте с заданными условиями - что будет больше А или B?

Ответ LLM : A будет больше потому , что .....

  1. Проведение эксперимента по заданным условиям. Результат: B > A

  2. Вопрос: Почему в тесте с заданными условиями B > A ?

Ответ: B > A потому , что ....

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

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

А принимать решения на основании прогнозов нейросетей - очень рискованно.

И IMHO вряд ли обьемы данных и вычислительные ресурсы способны изменить результат прогнозов LLM в условии практически отсутствия результатов экспериментов (ну по крайней мере в области которая мне интересна).

Большой вопрос к вам, читатели: пробовали ли вы когда-нибудь переписать современную задачу методами, которым вас учили в начале двухтысячных?

Я пробовал.

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

На дейлике (скрам аджайл все круто) рассказал - получил удивление и вопрос : а какую библиотеку использовал ?

Долго понять не мог - о чем вопрос . Поняв, очень загрустил. Это же задача третьего курса института, чему тут удивляться ?

Пожалуй, главное открытие в этом эксперименте — старые подходы не устарели. Они просто не вписываются в наш ритм.

да, мир изменился... Хотя с другой стороны, DBA это мало коснулось - реляционная алгебра со времен со времен Эдгара Кодда как была с 70-х годов прошлого века так и осталась .

А где ж "быстро"?

1987 - 1-й курс КАИ (Вычислительный центр КАИ на основе ЕС)

~1990-1991 - Вычислительный цент разобран, площади сданы в аренду.

По мне так не быстро а очень быстро.

Главная фишка 1С - русский синтаксис.

В очень далеком 1997 году , я был без работы - одна из шабашек была - "разработчик 1С". Меня хватило на 2 дня. Бросил и с тех пор больше никогда не пересекался с русскоязычным синтаксисом в принципе.

Еще раньше , в школе, по подростковой агрессивности ,нигилизму и максимализму - ненавидел Рапиру, но у нас уже был КУВТ Yamaha, так, что первым языком программирования на котором начал писать был Basic.

А с 1С вот же 28 лет по работе никак не пересекаюсь. Для DBA в общем то без разницы , как там 1Сники пишут, хоть на китайском и уйгурском.

Спасибо за идею теста

Гипотеза о лучшей производительности паттерна ARRAY перед паттерном MAX подтверждена экспериментально https://dzen.ru/a/aSVmNMQfaV04rJUT

при возникновении проблем с производительностью в проде первое, что проверяется - это именно что у нас там с БД

Устоявшаяся практика никогда не была равна эффективному решению и инженерному анализу.

В реальной жизни , уже скоро 6 лет как причины инцидентов операционной недоступности информационных систем неизменны:

90% - проблемы инфраструктуры (виртуализация, сеть, файловые системы в read only и т.п.)

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

1% - массовые вставки данных, не успели расширить файловые системы.

СУБД как причина инцидента - никогда не было.

Почему "первое, что проверяется - это именно что у нас там с БД" ? У нас кстати, тоже именно так - чуть, что сразу в отдел администрирования баз данных обращаются - "ой у нас тут что-то форма долго загружается "

Просто инженеры DBA более отзывчивые и обладают более широким взглядом на инфраструктуру в целом. Инженер DBA может посмотреть что-там по vmstat или itop , а инженер Unix запускать простейший select .... from pg_stat_activity вряд ли будет.

Везде пишут 

В этом то и проблема - все кто пишут никогда не проверяют рекомендации экспериментально . Максимум пару раз выполнить запрос и посмотреть explain.

То, что всё нужно тестировать синтетической нагрузкой , пока воспринимается как ересь.

и за границей так, вот ии выдаёт популярный совет

Да, DeepSeek основывается в основном на публикациях в китайском сегменте интернета. Ответы DeepSeek и "Ask Postgres", например , практически не отличаются.

Хотя DeepSeek иногда все таки выдает эксклюзив .

Разницу в последних примерах я отношу к погрешности измерений - у меня до 10% разброс между замерами получался,

Не кажется ли вам, что 10% это очень много для погрешности измерения ?

А какие вообще были статистические показатели измерений ? Сколько замеров делалось чтобы получить указанные границы значений ?

Сейчас уже мало кто знает и про ЕС ЭВМ и про ПЛ/1. 

Я из тех кто помнит и работал - ЕС , PL/I , Pascal , Fortran , Assembler.

Хотя конечно быстро все кончилось .

Меня всегда Pascal раздражал своей многобуквенностью. Мой первый реальный язык программирования после школы это C.

Я учился по этой книге
Я учился по этой книге

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

Еще бы уточнить , что означает термин "сервер СУБД перегружен" :

  • много запросов

  • много транзакций

  • много ожиданий

  • много прерываний

  • высокая утилизация CPU

  • высокая утилизация RAM

  • высокая утилизация IO

Ну и конечно уточнить - как определяются граничные условия ?

Параллельность тут вообще не при чем

Параллельные процессы , не узлы плана.

@Kilor

PostgreSQL Antipatterns: отказ от агрегатных функций = кратное ускорение

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

Кажется, мелочь,

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

Основная причина - Разница в загрузке CPU

  • Тест "MAX":

    • cpu_us = 98%, cpu_sy = 2%

    • Система почти полностью загружена пользовательскими процессами. Это указывает на высокую нагрузку от приложения, с минимальными затратами на системные вызовы.

  • Тест "ARRAY":

    • cpu_us = 77–79%, cpu_sy = 15–19%, cpu_id = 3–4%

    • Нагрузка более сбалансирована: значительная доля системных вызовов (cpu_sy), что может свидетельствовать об активной работе с ядром (например, частые системные вызовы или операции I/O).

Вывод: В тесте "MAX" CPU интенсивнее используется приложением, тогда как в "ARRAY" выше нагрузка на ядро.

Спасибо за наводку про очередной паттерн производительности !

1) В приведённом алгоритме решений оптимизации отсутствует принципиально важный пункт - нагрузочное тестирование и анализ результатов изменений

2)

База данных — это бутылочное горлышко. Начинайте оптимизацию оттуда. Индексы и EXPLAIN дают 80% результата за 20% усилий.

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

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

90% - проблемы логики приложений

8% - проблемы инфраструктуры

2% - неоптимальная настройка конфигурационных параметров СУБД

P.S. По итогам последних экспериментов и исследований - решения принятые на основании индексации и EXPLAIN могут дать совершенно неожиданные результаты.

что именно обозначают на вашем графике показатели «Операционная скорость» и «Точка наблюдения»?

В контексте оценки производительности СУБД используется метрика «операционная скорость». Данный показатель агрегируется за заданный временной период и представляет собой сумму двух сглаженных компонентов: взвешенного количества SQL-операций и результирующих строк. Процедура сглаживания динамических рядов указанных компонентов основана на применении скользящей медианы с окном в 60 минут. Наблюдения за метрикой фиксируются в дискретные моменты времени(точка наблюдения), соответствующие порядковому номеру минуты в ходе нагрузочного тестирования.

Источники:

  1. Корреляционный анализ ожиданий СУБД PostgreSQL - презентация по докладу, не попавшему на конференцию PGConf.СПб 2025 : https://dzen.ru/a/aJsZb6lzqxEd1KmR

  2. Статистический анализ производительности СУБД PostgreSQL: https://dzen.ru/a/aGYjGIt_KDOjmf35

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

А можно поподробнее ?

Информация

В рейтинге
Не участвует
Откуда
Россия
Зарегистрирован
Активность

Специализация

Администратор баз данных
Ведущий
SQL
PostgreSQL
Базы данных
Linux
Bash