Секрет 26,ч2. (Я знаю, что ничего не знаю: наводим резкость на small data )
Случился прецедент за гранью моего понимания, и по делу проходит снова справочник без статы:
на проме запрос
ежедневно отрабатывает в среднем за 1.5 мин, без проблем, как ни странно,
где mart$v - SCD2 вью для отбора последних версий, с идеей которой мы уже знакомы:
dict_product - пересобираемый под запрос тривиальный справочник в 1500 строк ( коды которых уникальны ), по которому стата не собрана, согласно параметров GUC.
Начиная с конца недели запрос стал падать по спиллу > 30 TB, при том, что особо ничего не поменялось.
В моей реальности, запрос тогда уж должен бы падать всегда, согласно Секрет 26, и объяснить нормальное поведение ДО начала деградации я не в состоянии.
Мне захотелось что-то выжать из этой аномалии, и вот что я узнал.
Если материализовать вью
в таблицу tst_mart из 1 млрд строк, то запрос
отбегает за 2м 18с, но при этом на материализацию tst_mart ушло 6 мин.
Если заглянуть в план, то ожидаемо увидим Broadcast дикта, ибо он без статы, что не критично :
А теперь к сути поста, которая меня крайне заинтересовала.
Если в исходном запросе в справочнике удалить все строки, или оставить, скажем одну из 1500, запрос отрабатывает на раз ( за 2 и 4 с соотв-но )
Это было неожиданно на фоне предыдущих секретов про пустые таблицы (Секрет 1,6).
Проверил снова запрос на полном справочнике - через 9 мин рухнул с workfile per query size limit exceeded.
Возникла шаткая гипотеза, что Broadcast сета из вью mart$v идет только на те узлы, где лежат строки справочника, что хоть как-то объяснило бы, почему запросы отработали.
Т.к. фактический план падающего запроса не проверить, я решил сравнить
теоретический план EXPLAIN с планом EXPLAIN ANALYZE, полученным из запроса на справочнике из 1 строки без статы.
Случился прецедент за гранью моего понимания, и по делу проходит снова справочник без статы:
на проме запрос
select cap_.agreement_rk, vc4_.product_bp_nm
from mart$v as cap_
join dict_product as vc4_
on cap_.product_bp_cd = vc4_.product_bp_cd
where cast('2025-11-26' as date) >= cap_.effective_from_dttm
and cast('2025-11-26' as date) < cap_.effective_to_dttm;
ежедневно отрабатывает в среднем за 1.5 мин, без проблем, как ни странно,
где mart$v - SCD2 вью для отбора последних версий, с идеей которой мы уже знакомы:
select *
from public.foo a
join (
select n, max(version_id) version_id from public.foo where version_id between :v_min and :v_max group by 1) c
using (n, version_id);
dict_product - пересобираемый под запрос тривиальный справочник в 1500 строк ( коды которых уникальны ), по которому стата не собрана, согласно параметров GUC.
Начиная с конца недели запрос стал падать по спиллу > 30 TB, при том, что особо ничего не поменялось.
В моей реальности, запрос тогда уж должен бы падать всегда, согласно Секрет 26, и объяснить нормальное поведение ДО начала деградации я не в состоянии.
Мне захотелось что-то выжать из этой аномалии, и вот что я узнал.
Если материализовать вью
select
from mart$v
where '2025-11-26'::date >= effective_from_dttm
and '2025-11-26'::date) < effective_to_dttm;
в таблицу tst_mart из 1 млрд строк, то запрос
explain analyze
select cap_.agreement_rk, vc4_.product_bp_nm
from tst_mart as cap_
join dict_product as vc4_
on cap_.product_bp_cd = vc4_.product_bp_cd
отбегает за 2м 18с, но при этом на материализацию tst_mart ушло 6 мин.
Если заглянуть в план, то ожидаемо увидим Broadcast дикта, ибо он без статы, что не критично :
Gather Motion 384:1 (slice2; segments: 384) (cost=0.00..1507.73 rows=1 width=264) (actual time=9.319..108483.528 rows=990063918 loops=1)
-> Hash Join (cost=0.00..1507.73 rows=1 width=264) (actual time=9.950..1315.095 rows=2583044 loops=1)
Hash Cond: (tst_mart.product_bp_cd = (tst1500.product_bp_cd)::text)
" Extra Text: (seg40) Hash chain length 1.0 avg, 2 max, using 1498 of 524288 buckets."
-> Seq Scan on tst_mart (cost=0.00..498.18 rows=2775858 width=14) (actual time=0.290..450.133 rows=2781093 loops=1)
-> Hash (cost=431.15..431.15 rows=1 width=264) (actual time=6.116..6.116 rows=1500 loops=1)
-> Broadcast Motion 384:384 (slice1; segments: 384) (cost=0.00..431.15 rows=1 width=264) (actual time=0.023..5.667 rows=1500 loops=1)
-> Seq Scan on tst1500 (cost=0.00..431.00 rows=1 width=264) (actual time=0.537..0.544 rows=12 loops=1)
Planning time: 13.347 ms
(slice0) Executor memory: 788K bytes.
" (slice1) Executor memory: 268K bytes avg x 384 workers, 268K bytes max (seg0)."
" (slice2) Executor memory: 4805K bytes avg x 384 workers, 4805K bytes max (seg0). Work_mem: 145K bytes max."
Memory used: 2129920kB
Optimizer: Pivotal Optimizer (GPORCA)
Execution time: 138661.777 ms
А теперь к сути поста, которая меня крайне заинтересовала.
Если в исходном запросе в справочнике удалить все строки, или оставить, скажем одну из 1500, запрос отрабатывает на раз ( за 2 и 4 с соотв-но )
Это было неожиданно на фоне предыдущих секретов про пустые таблицы (Секрет 1,6).
Проверил снова запрос на полном справочнике - через 9 мин рухнул с workfile per query size limit exceeded.
Возникла шаткая гипотеза, что Broadcast сета из вью mart$v идет только на те узлы, где лежат строки справочника, что хоть как-то объяснило бы, почему запросы отработали.
Т.к. фактический план падающего запроса не проверить, я решил сравнить
теоретический план EXPLAIN с планом EXPLAIN ANALYZE, полученным из запроса на справочнике из 1 строки без статы.
Оказалось, планы совпадают, а моя гипотеза несостоятельна.
А дело вот в чем.
Анализ плана (ниже фрагмент его критичных слайсов) дал следующий инсайд :
На первом шаге идет также Broadcast справочника, который Hash Join-им с большой табл-ой под вью, и вот этот результат Oops.. снова Broadcast-им.
Соотв-но, последний Broadcast для случая 1 строки в справочнике пересылает в 1500 строк меньше, чем для полного.
Для 0 строк в справочнике последний Broadcast соотв-но просто номинальный шаг.
Остается добавить, если выполнить исходный запрос на справочнике с собранной статой, запрос выполнился без спилла за 8.5 мин с ожидаемым Redistribute, но у меня и РГ другая,
не такая крутая, как у регламентного потока на проме.
Остается загадкой, а зачем нужен 2й Broadcast, кроме первого, который дал нам возможность сделать Hash-Join
А дело вот в чем.
Анализ плана (ниже фрагмент его критичных слайсов) дал следующий инсайд :
На первом шаге идет также Broadcast справочника, который Hash Join-им с большой табл-ой под вью, и вот этот результат Oops.. снова Broadcast-им.
Соотв-но, последний Broadcast для случая 1 строки в справочнике пересылает в 1500 строк меньше, чем для полного.
Для 0 строк в справочнике последний Broadcast соотв-но просто номинальный шаг.
Остается добавить, если выполнить исходный запрос на справочнике с собранной статой, запрос выполнился без спилла за 8.5 мин с ожидаемым Redistribute, но у меня и РГ другая,
не такая крутая, как у регламентного потока на проме.
Остается загадкой, а зачем нужен 2й Broadcast, кроме первого, который дал нам возможность сделать Hash-Join
Telegram
Greenplum secrets🎩
Секрет 26 (Не оставляйте крошки без внимания)
Мы успели осветить проблемы, возникающие на пустых таблицах
или при отсутствии статистики.
На этот раз тривиальный join 3х таблиц чуть не уронил нам сервер, а все потому, что по одной из них не было статистики.…
Мы успели осветить проблемы, возникающие на пустых таблицах
или при отсутствии статистики.
На этот раз тривиальный join 3х таблиц чуть не уронил нам сервер, а все потому, что по одной из них не было статистики.…
This media is not supported in your browser
VIEW IN TELEGRAM
В Лас-Вегасе стартовал финал чемпионата мира по Microsoft Excel. 24 финалиста в течение трёх дней решают сложные кейсы на вылет в легендарной HyperX Arena, где обычно соревнуются киберспортсмены. На кону рекордные $60 000 (4,7 млн рублей), а победитель получит чемпионский пояс в стиле WWE.
The Microsoft Excel World Championship finals have kicked off in Las Vegas. Over three days, 24 finalists will solve challenging knockout cases at the legendary HyperX Arena, where esports athletes typically compete. A record-breaking $60,000 (4.7 million rubles) is at stake, and the winner will receive a WWE-style championship belt.
The Microsoft Excel World Championship finals have kicked off in Las Vegas. Over three days, 24 finalists will solve challenging knockout cases at the legendary HyperX Arena, where esports athletes typically compete. A record-breaking $60,000 (4.7 million rubles) is at stake, and the winner will receive a WWE-style championship belt.
❤1
Ваш основной тул на работе в найме для ad-hoc расчетов // Your main tool as employee for ad-hoc calculations
Anonymous Poll
33%
Excel
6%
LibreOffice
0%
OpenOffice
1%
МойОфис
60%
select в DuckDB, SQLite, psql ...
Операция ITAS (Insert table as select) из A в B может создать спилл ? // Can ITAS (Insert table as select) operation from A to B create a spill?
Anonymous Poll
85%
Y
15%
N
Правильный ответ на опрос выше - 1(Да). Если в запросе есть сортировка ORDER BY, возможен спилл.
Напомню, что в ITAS(CTAS - не суть) это может давать хороший выигрыш по месту, о чем писал неоднократно, напр.
The correct answer to the poll above is 1.If the query contains an ORDER BY clause, a spill is possible.
As a reminder, in ITAS(CTAS - no matter), this can yield significant space savings, as I've written about repeatedly, for example:
Напомню, что в ITAS(CTAS - не суть) это может давать хороший выигрыш по месту, о чем писал неоднократно, напр.
The correct answer to the poll above is 1.If the query contains an ORDER BY clause, a spill is possible.
As a reminder, in ITAS(CTAS - no matter), this can yield significant space savings, as I've written about repeatedly, for example:
Telegram
Greenplum secrets🎩
Вечер пятницы, и самое время продолжить сортирную тему , начатую в начале недели, т.к. есть повод - появился резонный комментарий от одного из активных подписчиков:
Результат ожидаем. Zstd на отсортированной колонке даёт большее сжатие. Совершенно бесполезная…
Результат ожидаем. Zstd на отсортированной колонке даёт большее сжатие. Совершенно бесполезная…
👍2
А вы знали, что если в ватс апп сменить язык на болгарский то звонки работают без впн( хак от коллеги, не проверял пока)
😁3👏2
Вопрос 8
А кто знает, можно ли в GP сохранить результат запроса, в двумерный массив, не прибегая к PL/pgSQL
Does anyone know if it's possible to save the query result in a two-dimensional array in GP without using PL/pgSQL?
А кто знает, можно ли в GP сохранить результат запроса, в двумерный массив, не прибегая к PL/pgSQL
Does anyone know if it's possible to save the query result in a two-dimensional array in GP without using PL/pgSQL?
SQL> select regexp_matches('a := 1,b := 1', '(\w+)\s*:=\s*([^,]+)', 'g') as m
m
-----
{a,1}
{b,1}Forwarded from Smartyru
Друзья, выручайте, может у кого то завалялся фильм "Босиком по мостовой" с Швайгером, раздайте, плз
Интересно, в вашем ИТ есть собственный фреймворк для генерации SQL кода в ХД.
Или каждый разработчик A пишет готовый к исполнению код с нуля, даже если он повторяет ту же трасформаацию, написанную другим разработчиком B, пусть и на других таблицах.
Опрос ниже по такому поводу.
I wonder if your IT department has its own framework for generating SQL code in the data warehouse.
Or does each developer A write ready-made code from scratch, even if they're repeating the same transformation written by another developer B, albeit on different tables.
The survey is below
Или каждый разработчик A пишет готовый к исполнению код с нуля, даже если он повторяет ту же трасформаацию, написанную другим разработчиком B, пусть и на других таблицах.
Опрос ниже по такому поводу.
I wonder if your IT department has its own framework for generating SQL code in the data warehouse.
Or does each developer A write ready-made code from scratch, even if they're repeating the same transformation written by another developer B, albeit on different tables.
The survey is below
У вас есть in-house фреймворк для генерации ETL кода в DWH? Do you have an in-house framework for generating ETL code in DWH?
Anonymous Poll
53%
Y
47%
N
Проблема 1 (gprestore issue)
Бывает, требуется восстановить данеые из бэкапа по списку таблиц, но не в чистую БД, а в уже созданные чистые таблицы.
Если это делают не одни руки, а команда, то все может пойти не так гладко, как ожидалось.
Предположим, аналитик допустил ошибку, и передал в список на рестор лишнюю таблицу, или наоборот в БД нет какой-то подготовленной таблицы (или ее партиции) из списка.
Оказывается, в этом случае в 6-ке утилита gprestore рухнет при первой же ошибке.
Да, вы не ослышались, без использования ключа --on-error-continue - процесс восстановления прерывается при любой первой возникающей ошибке.
⁉️
Так в чем проблема - включили ключ и погнали ?
⚠️
А в том, что ключ этот имеет неожиданное поведение при работе с бекапсетами собранными с использованием --single-data-file и частичной вычиткой из оных.
Иными словами, если из бэкапа в сотни TB надо восстановить скажем 30% из 1000 таблиц, при каждом падении gprestore будет его перечитывать полностью и это уже проблема, которая может растянуться на часы, дни и т.д..
По хорошему, если бы для каждой таблы в бэкапе знать офсет ее DDL скрипта от начала ( а значит прямой указатель на сами данные, которые по идее
идут сразу после), то не пришлось бы перечитывать файл целиком. Собственно, так и работает gprestore без ключа, но до первого падения.
📌Решение: Согласно анонсу, в 6.29.1 данное недоразумение пофиксили, за что компании Аренадата +1 к карме!
Если кто проверял, дайте шуму, дайте знать!
Бывает, требуется восстановить данеые из бэкапа по списку таблиц, но не в чистую БД, а в уже созданные чистые таблицы.
Если это делают не одни руки, а команда, то все может пойти не так гладко, как ожидалось.
Предположим, аналитик допустил ошибку, и передал в список на рестор лишнюю таблицу, или наоборот в БД нет какой-то подготовленной таблицы (или ее партиции) из списка.
Оказывается, в этом случае в 6-ке утилита gprestore рухнет при первой же ошибке.
Да, вы не ослышались, без использования ключа --on-error-continue - процесс восстановления прерывается при любой первой возникающей ошибке.
⁉️
Так в чем проблема - включили ключ и погнали ?
⚠️
А в том, что ключ этот имеет неожиданное поведение при работе с бекапсетами собранными с использованием --single-data-file и частичной вычиткой из оных.
Иными словами, если из бэкапа в сотни TB надо восстановить скажем 30% из 1000 таблиц, при каждом падении gprestore будет его перечитывать полностью и это уже проблема, которая может растянуться на часы, дни и т.д..
По хорошему, если бы для каждой таблы в бэкапе знать офсет ее DDL скрипта от начала ( а значит прямой указатель на сами данные, которые по идее
идут сразу после), то не пришлось бы перечитывать файл целиком. Собственно, так и работает gprestore без ключа, но до первого падения.
📌Решение: Согласно анонсу, в 6.29.1 данное недоразумение пофиксили, за что компании Аренадата +1 к карме!
Если кто проверял, дайте шуму, дайте знать!
🤡5
#LEGO#фреймворк#парсинг динамического кода
Друзья, сверстал последний пост в уходящем году, а возможно в принципе на канале.
Меня очень занимает, если не вдохновляет, идея создания универсального фреймворка, в котором будут все возможные SQL трансформации, т.к. интуиция подсказывает, что их множество ограничено, хотя и велико.
Вероятно, у многих, кто использует свой in-house фреймворк, основной набор трансформаций T1, T2, ..., Tn реализован на PL/pgSQL
функциях, у каждой из которых есть параметры, задающие входную таблицу(-ы)
С большой вероятностью, из этих лего деталек T(i) вы строите достаточно сложные PL/pgSQL функции F для наполнения целевых витрин,
которые могут быть достаточно емкими по размеру, но построены по модульному принципу, т.е. представлены цепочкой трансформаций.
А если так, то вполне вероятно, что рано или поздно возникнет задача миграции определенной области ХД,
в которых используются F, на новый сервер.
И вот тут, если скажем исходные данные для F лежат в слое RDV, встает вопрос, какие именно таблицы требуются
для переносимого функционала.
Я имею ввиду, что сценарий, когда надо восстановить из бэкапа ряд таблиц RDV, представляющих набор исходных данных для
F, и выкатить поток с F на новом сервере,
чтобы бесшовно переключиться на работу ХД в новом контуре - вполне жизненная задача,
ибо миграция петабайтного ХД за один присест - задача практически невозможная как с технической точки зрения
так и экономически нецелесообразная, обычно такого слона едят по частям.
Ввиду того, что такая потребность в получении списка таблиц возникла у меня, я озаботился и написал
парсер для генерации списка исходных таблиц, которые используются в произвольной функции, построенной на операторах фрейма.
Повторюсь, что концептуально такая функция должна состоять из набора трансформаций T(i), представленных PL/pgSQL функциями с именованными параметрами.
Конкретно в моем случае я ловил пару параметров p_in_schema и p_in_table, задающих входы операторов фреймворка
исключая ad-hoc трансформацию, признаком которой является наличие параметра p_sql_text.
Также, поддержал случай, когда название таблицы в p_in_table параметризовано, т.е. завязано на название переменной,
значение которой объявлено либо в секции F declare, либо в ее основном блоке begin .. end.
Из интересного, я бы отметил, что мой любимый DeepSeek сделал 30% работы, остальное допиливал сам.
Особо пришлось повозиться с 2D массивами, т.к. надежды на то, что в 2D можно добавить 1D массив через array_append не оправдались.
Друзья, сверстал последний пост в уходящем году, а возможно в принципе на канале.
Меня очень занимает, если не вдохновляет, идея создания универсального фреймворка, в котором будут все возможные SQL трансформации, т.к. интуиция подсказывает, что их множество ограничено, хотя и велико.
Вероятно, у многих, кто использует свой in-house фреймворк, основной набор трансформаций T1, T2, ..., Tn реализован на PL/pgSQL
функциях, у каждой из которых есть параметры, задающие входную таблицу(-ы)
С большой вероятностью, из этих лего деталек T(i) вы строите достаточно сложные PL/pgSQL функции F для наполнения целевых витрин,
которые могут быть достаточно емкими по размеру, но построены по модульному принципу, т.е. представлены цепочкой трансформаций.
А если так, то вполне вероятно, что рано или поздно возникнет задача миграции определенной области ХД,
в которых используются F, на новый сервер.
И вот тут, если скажем исходные данные для F лежат в слое RDV, встает вопрос, какие именно таблицы требуются
для переносимого функционала.
Я имею ввиду, что сценарий, когда надо восстановить из бэкапа ряд таблиц RDV, представляющих набор исходных данных для
F, и выкатить поток с F на новом сервере,
чтобы бесшовно переключиться на работу ХД в новом контуре - вполне жизненная задача,
ибо миграция петабайтного ХД за один присест - задача практически невозможная как с технической точки зрения
так и экономически нецелесообразная, обычно такого слона едят по частям.
Ввиду того, что такая потребность в получении списка таблиц возникла у меня, я озаботился и написал
парсер для генерации списка исходных таблиц, которые используются в произвольной функции, построенной на операторах фрейма.
Повторюсь, что концептуально такая функция должна состоять из набора трансформаций T(i), представленных PL/pgSQL функциями с именованными параметрами.
Конкретно в моем случае я ловил пару параметров p_in_schema и p_in_table, задающих входы операторов фреймворка
исключая ad-hoc трансформацию, признаком которой является наличие параметра p_sql_text.
Также, поддержал случай, когда название таблицы в p_in_table параметризовано, т.е. завязано на название переменной,
значение которой объявлено либо в секции F declare, либо в ее основном блоке begin .. end.
Из интересного, я бы отметил, что мой любимый DeepSeek сделал 30% работы, остальное допиливал сам.
Особо пришлось повозиться с 2D массивами, т.к. надежды на то, что в 2D можно добавить 1D массив через array_append не оправдались.
🔥3👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Дорогие друзья! Желаю всем нам в новом году, чтобы ни у кого ничего не заклинило и шло все как по маслу!
😁8👏2
Друзья, 2026 год по восточному календарю — это год Красной Огненной Лошади, который начинается 17 февраля 2026 года и продлится до 5 февраля 2027-го, символизируя энергию, страсть, перемены и стремление к независимости.
Так как среди нас есть любители и мастера по шахматам, давно собирался это сделать - в 9:11 PM (21.11 мск) приглашаю всех, у кого есть аккаунтк на личесс на турнир, код на вход - 777, катнем 7 раундов, чтобы успеть до курантов,
https://lichess.org/swiss/FBQq3KT8
Так как среди нас есть любители и мастера по шахматам, давно собирался это сделать - в 9:11 PM (21.11 мск) приглашаю всех, у кого есть аккаунтк на личесс на турнир, код на вход - 777, катнем 7 раундов, чтобы успеть до курантов,
https://lichess.org/swiss/FBQq3KT8
lichess.org
HappyNewYearGreenplum by Wild Red Horse: Standard 3+2 #FBQq3KT8
1 players compete in the Dec 31, 2025 HappyNewYearGreenplum Swiss tournament organized by Wild Red Horse. Winner is not yet decided.
❤2

