Прошел месяц как Аренадата вышла на торги. Рост капитализации более 17% в руб пока ЦБ душит бизнесы ставкой. Лучшее IPO из ИТ компаний РФ. Емнип, все другие компании РФ падали по первой ниже цены размещения.
A month gone since Arenadata went public. Capitalization growth of more than 17% in rubles while the Central Bank stifles businesses with interest rates. It's the best IPO of Russian IT companies. If I remember correctly, all other Russian companies fell at the first below the placement price.
A month gone since Arenadata went public. Capitalization growth of more than 17% in rubles while the Central Bank stifles businesses with interest rates. It's the best IPO of Russian IT companies. If I remember correctly, all other Russian companies fell at the first below the placement price.
Greenplum secrets🎩
Секрет 17 (Однопроходные весы) Однажды многим предстоит сравнить 2 табл-ы. Скорее всего, 95% ( включая меня ) используют запрос вида: Secret 17 (Single-Pass Comparator) Many people will have to compare 2 tables at some point. Most likely, 95% (including…
Сейчас очень порадовал однопроходный метод из Секрета 17. На сравнение 2 табл A и Б порядка ~1 млн строк ушло ~0.5 c, тогда как чекнуть разницу через двойной except заняло > 34 с:
0 rows retrieved in 484 ms (execution: 422 ms, fetching: 62 ms) — fast diff
0 rows retrieved in 17 s 601 ms (execution: 969 ms, fetching: 16 s 632 ms) — 1st except A - B
0 rows retrieved in 16 s 480 ms (execution: 500 ms, fetching: 15 s 980 ms) — 2nd except B-A
Есть идеи, почему такой долгий fetching для операции ?
0 rows retrieved in 484 ms (execution: 422 ms, fetching: 62 ms) — fast diff
0 rows retrieved in 17 s 601 ms (execution: 969 ms, fetching: 16 s 632 ms) — 1st except A - B
0 rows retrieved in 16 s 480 ms (execution: 500 ms, fetching: 15 s 980 ms) — 2nd except B-A
Есть идеи, почему такой долгий fetching для операции ?
select * from A
except
select * from B
Cпилл, создаваемый запросом зависит от нагрузки на сервер со стороны других сессий ?
Do you think the spill generated by the request depends on the load on the server from other sessions?
Do you think the spill generated by the request depends on the load on the server from other sessions?
Anonymous Poll
65%
Yes
35%
No
Greenplum secrets🎩
Cпилл, создаваемый запросом зависит от нагрузки на сервер со стороны других сессий ?
Do you think the spill generated by the request depends on the load on the server from other sessions?
Do you think the spill generated by the request depends on the load on the server from other sessions?
Ответ на опрос в 2х словах: да, зависит.
Обоснование:
У нас ежедневно среди прочих выполняется запрос Q вида
Answer to the quiz above in 2 words: yes, it depends.
Justification:
We have a daily request Q among others
где foo - легковесная дельта distributed randomly из пары дюжин скалярных полей (int,text,date), idl.data_mart - фрагментирована (2 партиции) общим весом 144 GB.
6.11 Q создал спилл 24 TB ( в foo было 600k строк )
7.11 Q выполнился без спилла ( в foo было 6m строк общим весом 0.2 ГБ, т.е. на порядок больше) - план ниже.
Я создал синтетику из 600k строк из 24 int полей, чтобы воспроизвести прецедент 6.11 - запрос выполнился без спилла.
Я проверил гипотезу, а что если по foo не была собрана стата - запрос выполнился почти без спилла (16 GB)
В итоге, у меня остался один вопрос - а как в принципе GP6 смогла создать такой спилл,
если в плане только один Redistribute. Иного объяснения, кроме как то, что join выполнялся в виртуальной памяти 6.11.24,
т.е. на диске, я не нахожу.
where foo is a lightweight delta distributed randomly from a couple dozen scalar fields (int, text, date), idl.data_mart is fragmented (2 partitions) with a total weight of 144 GB.
6.11 Q created a 24 TB spill ( foo had 600k rows)
7.11 Q was executed without a spill ( foo had 6m rows with a total weight of 0.2 GB, i.e. an order of magnitude more) - the plan is below.
I created synthetics from 600k rows from 24 int fields to reproduce the 6.11 precedent - the query was executed without a spill.
I checked the hypothesis, what if there was no statistics collected for foo - the query was executed almost without a spill (16 GB)
As a result, I have ONLY one unresolved question - HOW COME that GP6 was heroically able to create such big spill,
if there is only one Redistribute in the plan. I can't find any other explanation other than that join was executed in virtual memory on 6.11.24, i.e. on disk.
Обоснование:
У нас ежедневно среди прочих выполняется запрос Q вида
Answer to the quiz above in 2 words: yes, it depends.
Justification:
We have a daily request Q among others
select true
from (select counterparty_rk
from stg.foo
) s
where not exists(select 1 from idl.data_mart t where s.counterparty_rk = t.counterparty_rk)
limit 1
где foo - легковесная дельта distributed randomly из пары дюжин скалярных полей (int,text,date), idl.data_mart - фрагментирована (2 партиции) общим весом 144 GB.
6.11 Q создал спилл 24 TB ( в foo было 600k строк )
7.11 Q выполнился без спилла ( в foo было 6m строк общим весом 0.2 ГБ, т.е. на порядок больше) - план ниже.
Я создал синтетику из 600k строк из 24 int полей, чтобы воспроизвести прецедент 6.11 - запрос выполнился без спилла.
Я проверил гипотезу, а что если по foo не была собрана стата - запрос выполнился почти без спилла (16 GB)
В итоге, у меня остался один вопрос - а как в принципе GP6 смогла создать такой спилл,
если в плане только один Redistribute. Иного объяснения, кроме как то, что join выполнялся в виртуальной памяти 6.11.24,
т.е. на диске, я не нахожу.
where foo is a lightweight delta distributed randomly from a couple dozen scalar fields (int, text, date), idl.data_mart is fragmented (2 partitions) with a total weight of 144 GB.
6.11 Q created a 24 TB spill ( foo had 600k rows)
7.11 Q was executed without a spill ( foo had 6m rows with a total weight of 0.2 GB, i.e. an order of magnitude more) - the plan is below.
I created synthetics from 600k rows from 24 int fields to reproduce the 6.11 precedent - the query was executed without a spill.
I checked the hypothesis, what if there was no statistics collected for foo - the query was executed almost without a spill (16 GB)
As a result, I have ONLY one unresolved question - HOW COME that GP6 was heroically able to create such big spill,
if there is only one Redistribute in the plan. I can't find any other explanation other than that join was executed in virtual memory on 6.11.24, i.e. on disk.
👍1
Limit (cost=0.00..15089.37 rows=1 width=1) (actual time=1954.485..1954.485 rows=0 loops=1)
-> Gather Motion 864:1 (slice2; segments: 864) (cost=0.00..15089.37 rows=1 width=1) (actual time=1954.445..1954.445 rows=0 loops=1)
-> Limit (cost=0.00..15089.37 rows=1 width=1) (actual time=0.000..1926.607 rows=0 loops=1)
-> Result (cost=0.00..15089.37 rows=1147 width=1) (actual time=0.000..1926.600 rows=0 loops=1)
-> Result (cost=0.00..15089.37 rows=1147 width=1) (actual time=0.000..1926.596 rows=0 loops=1)
" Filter: (COALESCE((count()), '0'::bigint) = '0'::bigint)"
-> Result (cost=0.00..15089.27 rows=2868 width=8) (actual time=0.000..1926.592 rows=0 loops=1)
-> Hash Right Join (cost=0.00..15089.25 rows=2868 width=8) (actual time=0.000..1926.588 rows=0 loops=1)
Hash Cond: (data_mart.counterparty_rk = foo.counterparty_rk)
-> Result (cost=0.00..1410.20 rows=3407709 width=16) (never executed)
-> HashAggregate (cost=0.00..1355.67 rows=3407709 width=16) (never executed)
Group Key: data_mart.counterparty_rk
-> Sequence (cost=0.00..832.09 rows=3407709 width=8) (never executed)
-> Partition Selector for data_mart (dynamic scan id: 1) (cost=10.00..100.00 rows=1 width=4) (never executed)
Partitions selected: 2 (out of 2)
-> Dynamic Seq Scan on data_mart (dynamic scan id: 1) (cost=0.00..832.09 rows=3407709 width=8) (never executed)
-> Hash (cost=447.69..447.69 rows=2868 width=8) (actual time=0.000..1925.847 rows=0 loops=1)
-> Redistribute Motion 864:864 (slice1; segments: 864) (cost=0.00..447.69 rows=2868 width=8) (actual time=0.000..1925.846 rows=0 loops=1)
Hash Key: foo.counterparty_rk
-> Seq Scan on foo (cost=0.00..431.79 rows=2868 width=8) (actual time=0.000..1040.971 rows=0 loops=1)
" Filter: (COALESCE((counterparty_rk)::text, '-1'::text) <> '-1'::text)"
Planning time: 49.665 ms
(slice0) Executor memory: 711K bytes.
" (slice1) Executor memory: 212K bytes avg x 864 workers, 212K bytes max (seg0)."
" (slice2) Executor memory: 1215K bytes avg x 864 workers, 1215K bytes max (seg0)."
Memory used: 229376kB
Optimizer: Pivotal Optimizer (GPORCA)
Execution time: 2173.226 ms
Думаю, стоит отдельно остановиться на вопросах моего самого активного подписчика @GaRin_1979, вызванных последним квизом:
Итак, по порядку.
Увы, машины времени нет, чтобы получить идентичную табл-у foo. План был на 99% тот, что в посте, исходя из вводных, что я давал.
Если же по таблице foo не было статы (вероятность этого ничтожно мала исходя из GUC), то в плане будет Hash anti-join вместо Right Join
и другой порядок операторов, но на спилл в данном случае это влияет никак, исходя из моих тестов, которые также вошли в пост.
1) Полный запрос дан в посте, просто названия табл другие и чтобы не оттенять суть, я исключил условие where coalesce(..) != '-1', которое осталось в плане.
Запрос выполнился, не упал. Конкретно для этого запроса это впервые за последние 30 дн. В принципе, с авг 23г аналогов
набралось с десяток, когдаб например, пытаешься воспроизвести спилл в pl/pgsql ф-ии на тех же входных параметрах под другой РГ, а он нулевой.
Спилл у нас собирает коллектор ежеминутно из gp_toolkit.gp_workfile_entries - Слава нашим DBA!
Соотв-но, в своих выводах опираюсь на историю спиллов, зафиксированную оным.
2) В gp_toolkit.gp_workfile_entries.optype обнаружен только HashJoin.
В моей реальности, Redistribute Motion ( а в плане он единственный) не может создать спилл больше, чем табл-а, которую он перераспределяет, в которой было 600к строк.
Или я не прав? Гипотеза, что эта таблица весила 24 TB несостоятельна, т.к. она создана за 1 сек. Гипотеза, что редистрибутилась idl.data_mart,
в сжатом виде 144 GB (zstd1) тоже несостоятельна - если взять as is ( т.е. без компрессии) 10% случайных записей из ее 3 млрд строк - это лишь 50 ГБ. Т.е. ее Redistribute мог бы дать 0.5 - 1 TB max.
Если бы в плане был ее Broadcast, то 24 TB бы не отделались, но и время бы было не 2000 сек на запрос.
Т.е. у меня в принципе нет объяснения произошедшему.
3) off
Итак, по порядку.
Увы, машины времени нет, чтобы получить идентичную табл-у foo. План был на 99% тот, что в посте, исходя из вводных, что я давал.
Если же по таблице foo не было статы (вероятность этого ничтожно мала исходя из GUC), то в плане будет Hash anti-join вместо Right Join
и другой порядок операторов, но на спилл в данном случае это влияет никак, исходя из моих тестов, которые также вошли в пост.
1) Полный запрос дан в посте, просто названия табл другие и чтобы не оттенять суть, я исключил условие where coalesce(..) != '-1', которое осталось в плане.
Запрос выполнился, не упал. Конкретно для этого запроса это впервые за последние 30 дн. В принципе, с авг 23г аналогов
набралось с десяток, когдаб например, пытаешься воспроизвести спилл в pl/pgsql ф-ии на тех же входных параметрах под другой РГ, а он нулевой.
Спилл у нас собирает коллектор ежеминутно из gp_toolkit.gp_workfile_entries - Слава нашим DBA!
Соотв-но, в своих выводах опираюсь на историю спиллов, зафиксированную оным.
2) В gp_toolkit.gp_workfile_entries.optype обнаружен только HashJoin.
В моей реальности, Redistribute Motion ( а в плане он единственный) не может создать спилл больше, чем табл-а, которую он перераспределяет, в которой было 600к строк.
Или я не прав? Гипотеза, что эта таблица весила 24 TB несостоятельна, т.к. она создана за 1 сек. Гипотеза, что редистрибутилась idl.data_mart,
в сжатом виде 144 GB (zstd1) тоже несостоятельна - если взять as is ( т.е. без компрессии) 10% случайных записей из ее 3 млрд строк - это лишь 50 ГБ. Т.е. ее Redistribute мог бы дать 0.5 - 1 TB max.
Если бы в плане был ее Broadcast, то 24 TB бы не отделались, но и время бы было не 2000 сек на запрос.
Т.е. у меня в принципе нет объяснения произошедшему.
3) off
Forwarded from Ринат Галямов
Два вопроса:
1) план точно от запросп приведённого в статье? Можно полный запрос, который падал по спилам?
2) хэш таблицы создаются по умолчанию несжатые. И 114 гб вполне могут в несжатом виде занять > 24 тб
+ редистрибутив - и вылетели за лимиты.
Что покажет
Show gp_workfile_compresson
?
1) план точно от запросп приведённого в статье? Можно полный запрос, который падал по спилам?
2) хэш таблицы создаются по умолчанию несжатые. И 114 гб вполне могут в несжатом виде занять > 24 тб
+ редистрибутив - и вылетели за лимиты.
Что покажет
Show gp_workfile_compresson
?
NOT IN ('1','2') пробрасывается при чтении внешней табл-ы по JDBC через PXF?
Is Filter NOT IN ('1','2') pushed down when reading external Oracle table via PXF?
Is Filter NOT IN ('1','2') pushed down when reading external Oracle table via PXF?
Anonymous Quiz
42%
Y
58%
N
Секрет 21(И снова Разделяй и властвуй)
Секрет уходит корнями в эмуляцию MPP в PostgreSQL 9 на одном из пилотных проектов BigData в АШАН.
Мне поручили рефакторинг старой legacy системы, где французы переливали из Oracle ежедневно 0.5 млрд строк
на FTP, csv c которого загружались в PG. Горе в то, что Выгрузка была неинкрементальна и со временем этот объем только отрастал.
Мы с DevOps-ом настроили FDW для прямой шины Oracle => PG и это уже было в 2-3 раза быстрее, но SLA по готовности данных
для топ-менеджмента к 7 утра все еще выполнен не был. Лирика в прошлом, теперь к сути.
Я задумался, а что если разбить поток данных из Oracle на подмножества, подняв для каждого свой sh-скрипт на стороне PG,
который стягивает свою часть данных. Хорошо помню, что идея оказалась состоятельна, причем после перебора число ниток = 16, на которые распараллеливался поток,
оказалось оптимальным и совпало с числом CPU на сервере.
Сегодня я решил проверить, работает ли тот же подход для связки PXF + Oracle в GP, и первый же тест убедил меня, что да,
идея распараллеливания запроса хард-код фильтрами состоятельна и подход можно брать вооружение.
Не буду грузить вас SQL скриптами в этот раз, донесу лишь суть эксперимента и вывод.
Возьмем внешнюю табл-у X в Oracle с 35 полями И запрос Q с прома, который регулярно выгружает данные за период из X в stg табл-у в GP -
за сегодня получим 15 млн строк в среднем за 5 мин 13 сек.
Найдем в X поле с низкой кардинальностью, скажем code имеющее в нашем случае 15 различных коротких значений вида '00', '19' и др. и составим
гистограмму распределения числа строк по кодам.
Допустим, фильтру F code in ('00', '19') соотв-ет 6 млн строк в сумме, остальному набору 13 кодов - 9 млн строк.
Выполним в параллели 2 запроса Q каждый с своим фильтром F и увидим, что запросы выполнились в среднем за 2 мин 7 сек и 2 мин 50 сек соотв-но,
т.е. итоговое время для 2х параллельных ниток составило 2 мин 50 сек, что дает ускорение на 46%.
Можно и дальше повысить коэффициент распараллеливания, но это тема отдельного исследования.
В принципе, если в таблице нет поля, по которому можно распараллелится, можно на источнике создать вью с вычислимым полем,
которое условно будет бить все множество на нужное нам число примерно равных частей, напр. это может быть код первого символа в rowid Oracle табл-ы
по модулю 10, если мы хотим выгружать внешку в 10 параллельных потоков.
Отмечу, что рез-ты усреднены по двум прогонам, в рамках которых они близки к среднему.
Вывод: Выгрузку данных из внешней таблицы можно существенно ускорить, если распараллелить ее собственными средствами.
Секрет уходит корнями в эмуляцию MPP в PostgreSQL 9 на одном из пилотных проектов BigData в АШАН.
Мне поручили рефакторинг старой legacy системы, где французы переливали из Oracle ежедневно 0.5 млрд строк
на FTP, csv c которого загружались в PG. Горе в то, что Выгрузка была неинкрементальна и со временем этот объем только отрастал.
Мы с DevOps-ом настроили FDW для прямой шины Oracle => PG и это уже было в 2-3 раза быстрее, но SLA по готовности данных
для топ-менеджмента к 7 утра все еще выполнен не был. Лирика в прошлом, теперь к сути.
Я задумался, а что если разбить поток данных из Oracle на подмножества, подняв для каждого свой sh-скрипт на стороне PG,
который стягивает свою часть данных. Хорошо помню, что идея оказалась состоятельна, причем после перебора число ниток = 16, на которые распараллеливался поток,
оказалось оптимальным и совпало с числом CPU на сервере.
Сегодня я решил проверить, работает ли тот же подход для связки PXF + Oracle в GP, и первый же тест убедил меня, что да,
идея распараллеливания запроса хард-код фильтрами состоятельна и подход можно брать вооружение.
Не буду грузить вас SQL скриптами в этот раз, донесу лишь суть эксперимента и вывод.
Возьмем внешнюю табл-у X в Oracle с 35 полями И запрос Q с прома, который регулярно выгружает данные за период из X в stg табл-у в GP -
за сегодня получим 15 млн строк в среднем за 5 мин 13 сек.
Найдем в X поле с низкой кардинальностью, скажем code имеющее в нашем случае 15 различных коротких значений вида '00', '19' и др. и составим
гистограмму распределения числа строк по кодам.
Допустим, фильтру F code in ('00', '19') соотв-ет 6 млн строк в сумме, остальному набору 13 кодов - 9 млн строк.
Выполним в параллели 2 запроса Q каждый с своим фильтром F и увидим, что запросы выполнились в среднем за 2 мин 7 сек и 2 мин 50 сек соотв-но,
т.е. итоговое время для 2х параллельных ниток составило 2 мин 50 сек, что дает ускорение на 46%.
Можно и дальше повысить коэффициент распараллеливания, но это тема отдельного исследования.
В принципе, если в таблице нет поля, по которому можно распараллелится, можно на источнике создать вью с вычислимым полем,
которое условно будет бить все множество на нужное нам число примерно равных частей, напр. это может быть код первого символа в rowid Oracle табл-ы
по модулю 10, если мы хотим выгружать внешку в 10 параллельных потоков.
Отмечу, что рез-ты усреднены по двум прогонам, в рамках которых они близки к среднему.
Вывод: Выгрузку данных из внешней таблицы можно существенно ускорить, если распараллелить ее собственными средствами.
Secret 21 (Divide and Conquer Again)
The secret has its roots in the emulation of MPP in PostgreSQL 9 on one of the BigData pilot projects at Auchan.
I was tasked with refactoring an old legacy system where the French were transferring 0.5 billion rows daily from Oracle
to FTP, csv from which they were loaded into PG. The trouble was that the Unloading was non-incremental and over time this volume only grew.
DevOps and I set up an FDW for a direct Oracle => PG bus and it was already 2-3 times faster, but the SLA for data readiness
for top management by 7 am was still not met. The lyrics are in the past, now to the point.
I wondered, what if we split the data flow from Oracle into subsets, raising for each its own sh-script on the PG side,
which pulls its part of the data. I remember well that the idea turned out to be viable, and after sorting the number of threads = 16, on which the flow was parallelized,
turned out to be optimal and coincided with the number of CPUs on the server.
Today I decided to check whether the same approach works for the PXF + Oracle bundle in GP, and the very first test convinced me that yes,
the idea of parallelizing a query with hard code filters is viable and the approach can be taken up.
I will not burden you with SQL scripts this time, I will only convey the essence of the experiment and the conclusion.
Let's take an external table X in Oracle with 35 fields And a query Q from production flow, which regularly unloads data for a period from X to the stg table in GP -
today we will get 15 million rows on average in 5 minutes 13 seconds.
Let's find a low-cardinality field in X, say code, which in our case has 15 different short values like '00', '19', etc., and create a histogram of the distribution of the number of rows by codes.
Let's assume that the filter F code in ('00', '19') corresponds to 6 million rows in total, and the rest of the set of 13 codes corresponds to 9 million rows.
Let's execute 2 parallel queries Q, each with its own filter F, and see that the queries were executed on average in 2 min 7 sec and 2 min 50 sec, respectively,
i.e. the total time for 2 parallel threads was 2 min 50 sec, which gives an acceleration of 46%.
It is possible to further increase the parallelization coefficient, but this is a topic for a separate study.
In principle, if the table does not have a field that can be parallelized, you can create a view with a computable field on the source,
which will conditionally split the entire set into the number of approximately equal parts we need, for example, this could be the code of the first character in the Oracle table rowid
modulo 10, if we want to unload the external data into 10 parallel streams.
Note that the results are averaged over two runs, within which they are close to the average.
Conclusion: Unloading data from an external table can be significantly accelerated if you parallelize it using your own tools.
The secret has its roots in the emulation of MPP in PostgreSQL 9 on one of the BigData pilot projects at Auchan.
I was tasked with refactoring an old legacy system where the French were transferring 0.5 billion rows daily from Oracle
to FTP, csv from which they were loaded into PG. The trouble was that the Unloading was non-incremental and over time this volume only grew.
DevOps and I set up an FDW for a direct Oracle => PG bus and it was already 2-3 times faster, but the SLA for data readiness
for top management by 7 am was still not met. The lyrics are in the past, now to the point.
I wondered, what if we split the data flow from Oracle into subsets, raising for each its own sh-script on the PG side,
which pulls its part of the data. I remember well that the idea turned out to be viable, and after sorting the number of threads = 16, on which the flow was parallelized,
turned out to be optimal and coincided with the number of CPUs on the server.
Today I decided to check whether the same approach works for the PXF + Oracle bundle in GP, and the very first test convinced me that yes,
the idea of parallelizing a query with hard code filters is viable and the approach can be taken up.
I will not burden you with SQL scripts this time, I will only convey the essence of the experiment and the conclusion.
Let's take an external table X in Oracle with 35 fields And a query Q from production flow, which regularly unloads data for a period from X to the stg table in GP -
today we will get 15 million rows on average in 5 minutes 13 seconds.
Let's find a low-cardinality field in X, say code, which in our case has 15 different short values like '00', '19', etc., and create a histogram of the distribution of the number of rows by codes.
Let's assume that the filter F code in ('00', '19') corresponds to 6 million rows in total, and the rest of the set of 13 codes corresponds to 9 million rows.
Let's execute 2 parallel queries Q, each with its own filter F, and see that the queries were executed on average in 2 min 7 sec and 2 min 50 sec, respectively,
i.e. the total time for 2 parallel threads was 2 min 50 sec, which gives an acceleration of 46%.
It is possible to further increase the parallelization coefficient, but this is a topic for a separate study.
In principle, if the table does not have a field that can be parallelized, you can create a view with a computable field on the source,
which will conditionally split the entire set into the number of approximately equal parts we need, for example, this could be the code of the first character in the Oracle table rowid
modulo 10, if we want to unload the external data into 10 parallel streams.
Note that the results are averaged over two runs, within which they are close to the average.
Conclusion: Unloading data from an external table can be significantly accelerated if you parallelize it using your own tools.
Используете подход для ускорения PXF, описанный в Секрете 21 ?
Are you using the PXF acceleration approach described in Secret 21?
Are you using the PXF acceleration approach described in Secret 21?
Anonymous Poll
48%
Y
30%
N
22%
У нас другой метод __We use different approach__
Greenplum secrets🎩
NOT IN ('1','2') пробрасывается при чтении внешней табл-ы по JDBC через PXF?
Is Filter NOT IN ('1','2') pushed down when reading external Oracle table via PXF?
Is Filter NOT IN ('1','2') pushed down when reading external Oracle table via PXF?
Что касается квиза про NOT IN, то VMWare утверждает , что IN тоже не пробрасывается в Oracle ( по jdbc ).Но тесты в ГП 6.25 (сборка от Аренадата ) говорят об обратном. Рез-т статистически значим. As for the quiz about NOT IN , VMWare claims that IN is also not pushed down to Oracle (by jdbc). However tests in GP 6.25 (build by Arenadata) say the opposite. The result is statistically significant.
Greenplum secrets🎩
Что касается квиза про NOT IN, то VMWare утверждает , что IN тоже не пробрасывается в Oracle ( по jdbc ).Но тесты в ГП 6.25 (сборка от Аренадата ) говорят об обратном. Рез-т статистически значим. As for the quiz about NOT IN , VMWare claims that IN is also…
Vmware заблокировали. Нет больше документации по greenplum. Ссылка выше вчера еще была доступна. Vmware has been blocked. No more documentation on greenplum. The link above was still available yesterday.
😢5
Секрет 777 (Доверяй, но проверяй!)
В секрете 19 мы коснулись темы отбора последних версий записей в SCD2 таблице.
Действительно, такая задача - это рутинная операция в нашем DWH, которая решается типовым запросом
Secret 777 (Trust, but check!)
In secret 19 we touched on the topic of selecting the latest versions of records in the SCD2 table.
Indeed, such a task is a routine operation in our DWH, which is solved by a standard query
Как-то заметил, что выгрузка инкремента из 50 млрд-ной таблицы транзакций в S3 таким способом дает в лучшем случае спилл 20 TB,
в худшем - падает с ошибкой workfile per query size limit exceeded.
Вскрытие показало, что фильтр на версию нужно наложить дважды, как к CTE, вычисляющий актуальные версии ключей так и к самой табл-е,
к которой join-им CTE, что было весьма неочевидно:
Once I noticed that unloading an increment from a 50 billion transaction table to S3 in this way gives a 20 TB spill at best,
at worst - crashes with the error 'workfile per query size limit exceeded'.
Analysis revealed that the version filter needs to be applied twice, both to the CTE that calculates the current versions of the keys and to the table itself,
to which the CTE is joined, which was quite unobvious:
Данная мера свела спилл к нулю, Execution time сократился в 31 раз.
На фото планы запросов для жаждущих ( справа - оптимальный ) - как будто ничего особенного, мелочь добавилась.
Если буду писать свой компилятор БД, обещаю учесть этот факап, чтобы условие подставлялось авто-МАТОМ,
если иного нет.
This measure eliminated spill, and execution time was reduced by 31 times.
In the photo, there are query plans for the thirsty (on the right - the optimal one) - nothing special, a small thing was added.
If I write my own DB compiler, I promise to take this fuckup into account so that the condition is substituted a.u.t.o.m.a.t.i.c.a.l.l.y,
unless otherwise stated.
В секрете 19 мы коснулись темы отбора последних версий записей в SCD2 таблице.
Действительно, такая задача - это рутинная операция в нашем DWH, которая решается типовым запросом
Secret 777 (Trust, but check!)
In secret 19 we touched on the topic of selecting the latest versions of records in the SCD2 table.
Indeed, such a task is a routine operation in our DWH, which is solved by a standard query
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)
Как-то заметил, что выгрузка инкремента из 50 млрд-ной таблицы транзакций в S3 таким способом дает в лучшем случае спилл 20 TB,
в худшем - падает с ошибкой workfile per query size limit exceeded.
Вскрытие показало, что фильтр на версию нужно наложить дважды, как к CTE, вычисляющий актуальные версии ключей так и к самой табл-е,
к которой join-им CTE, что было весьма неочевидно:
Once I noticed that unloading an increment from a 50 billion transaction table to S3 in this way gives a 20 TB spill at best,
at worst - crashes with the error 'workfile per query size limit exceeded'.
Analysis revealed that the version filter needs to be applied twice, both to the CTE that calculates the current versions of the keys and to the table itself,
to which the CTE is joined, which was quite unobvious:
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)
where a.version_id between :v_min and :v_max
Данная мера свела спилл к нулю, Execution time сократился в 31 раз.
На фото планы запросов для жаждущих ( справа - оптимальный ) - как будто ничего особенного, мелочь добавилась.
Если буду писать свой компилятор БД, обещаю учесть этот факап, чтобы условие подставлялось авто-МАТОМ,
если иного нет.
This measure eliminated spill, and execution time was reduced by 31 times.
In the photo, there are query plans for the thirsty (on the right - the optimal one) - nothing special, a small thing was added.
If I write my own DB compiler, I promise to take this fuckup into account so that the condition is substituted a.u.t.o.m.a.t.i.c.a.l.l.y,
unless otherwise stated.
🔥2
Какова разница в часах What is the difference in hours ?
select to_timestamp(449611200) at time zone 'europe/moscow'
union all select to_timestamp(449611200 + 3600) at time zone 'europe/moscow'
select to_timestamp(449611200) at time zone 'europe/moscow'
union all select to_timestamp(449611200 + 3600) at time zone 'europe/moscow'
Anonymous Poll
10%
0
81%
1
9%
2
Greenplum secrets🎩
Какова разница в часах What is the difference in hours ?
select to_timestamp(449611200) at time zone 'europe/moscow'
union all select to_timestamp(449611200 + 3600) at time zone 'europe/moscow'
select to_timestamp(449611200) at time zone 'europe/moscow'
union all select to_timestamp(449611200 + 3600) at time zone 'europe/moscow'
Верный ответ: 2. Спасибо всем, кто знал почему и не выдал. На самом деле в ряде случаев 0 тоже будет корректным ответом, но в контексте вопроса стрелки часов в России 1 апр 1984 переводили на летнее время, т.е. на час вперед:
Thanks to everyone who knew why and didn't give solution in comments.
In fact, 0 could also be correct, but in the context of the question, the clock in Russia were switched to summer time on April 1, 1984,
i.e. an hour ahead:
Thanks to everyone who knew why and didn't give solution in comments.
In fact, 0 could also be correct, but in the context of the question, the clock in Russia were switched to summer time on April 1, 1984,
i.e. an hour ahead:
1984-03-31 23:00:00.000000
1984-04-01 01:00:00.000000
🔥3💩1
А вот интересно, сколько платных ИТ курсов вы прошли(проходите) за последний год ?
I wonder how many paid IT courses you've got (are taking) over the past year?
I wonder how many paid IT courses you've got (are taking) over the past year?
Anonymous Poll
57%
0
9%
1
8%
2
2%
> 2
11%
пока только бесплатные (so far only free ones)
11%
за счет компании-работодателя(at the expense of the employer company)
1%
Некогда, погружение в GP отнимает все время (No time, diving into GP takes up all my time)
Секрет 22 (Скупой платит дважды)
Часто разработчик выбирает тип данных, которого точно хватит на все случаи жизни, напр.
если надо закодировать пол человека цифрами(0-Ж, 1-М, 2-иное), то smalliint вполне хватит.
Аналогично, если мы захотим закодировать ID человека в разрезе городов их рождения, то 4 млрд значений в
int хватит и мы вряд ли захотим в физмодели использовать int8, т.к. уникальный ключ CITY + ID
точно покроет все возможные потребности.
Однако, оказывается, что если по каким-то причинам для такого ID в 2 таблицах DWH будут использованы
int и int8, то даже при согласованных хэшах джойна таких таблиц мы получим Redistribute.
Наглядный пример уже есть тут
Создадим 2 тестовые таблицы с одним полем id с типом int и int8, соответственно, и распределим данные по этому полю id:
Secret 22 (A miser pays twice)
Often the developer chooses a data type that is definitely enough for all occasions, for example,
if we need to encode a person's gender in numbers (0-F, 1-M, 2-other), then smalliint is quite enough.
Similarly, if we want to encode a person's ID assigned to their cities of birth, then 4 billion values in
int will be enough and we are unlikely to want to use int8 in the physical model, since the unique key CITY + ID
will definitely cover all possible needs.
However, it turns out that if for some reason for such an ID in 2 DWH tables
int and int8 are used, then even with consistent hashes of the join of such tables we will get Redistribute.
Let's create 2 test tables with one id field with the int and int8 types, respectively, and distribute the data by this id field:
Посмотрим на план запроса:Let's look at the query plan:
Как видим, первая таблица все равно перераспределилась по кластеру, хотя ключ ее распределения согласован с ключом второй табл-ы.
Но это еще не все. Оказывается, что сжатая zstd с int весит на 116% больше такой же с int8 ( см.фото ).
Выражаю признательность самому активному подписчику @GaRin_1979 за то, что подсветил феномен с размером int и int8 и поделился ссылкой , которая дала идею данному посту. Отдельный респект автору, который провел большое исследование и опубликовал его рез-т на хабре.
Часто разработчик выбирает тип данных, которого точно хватит на все случаи жизни, напр.
если надо закодировать пол человека цифрами(0-Ж, 1-М, 2-иное), то smalliint вполне хватит.
Аналогично, если мы захотим закодировать ID человека в разрезе городов их рождения, то 4 млрд значений в
int хватит и мы вряд ли захотим в физмодели использовать int8, т.к. уникальный ключ CITY + ID
точно покроет все возможные потребности.
Однако, оказывается, что если по каким-то причинам для такого ID в 2 таблицах DWH будут использованы
int и int8, то даже при согласованных хэшах джойна таких таблиц мы получим Redistribute.
Наглядный пример уже есть тут
Создадим 2 тестовые таблицы с одним полем id с типом int и int8, соответственно, и распределим данные по этому полю id:
Secret 22 (A miser pays twice)
Often the developer chooses a data type that is definitely enough for all occasions, for example,
if we need to encode a person's gender in numbers (0-F, 1-M, 2-other), then smalliint is quite enough.
Similarly, if we want to encode a person's ID assigned to their cities of birth, then 4 billion values in
int will be enough and we are unlikely to want to use int8 in the physical model, since the unique key CITY + ID
will definitely cover all possible needs.
However, it turns out that if for some reason for such an ID in 2 DWH tables
int and int8 are used, then even with consistent hashes of the join of such tables we will get Redistribute.
Let's create 2 test tables with one id field with the int and int8 types, respectively, and distribute the data by this id field:
create table tst_join_types_int (id int)
with (appendonly=true , orientation=row, compresstype=zstd, compresslevel=1)
DISTRIBUTED BY (id);
create table tst_join_types_int8 (id int8)
with (appendonly=true , orientation=row, compresstype=zstd, compresslevel=1)
DISTRIBUTED BY (id);
insert into tst_join_types_int
select gen
from generate_series(1,1000000) gen;
insert into tst_join_types_int8
select gen
from generate_series(1,1000000) gen;
Посмотрим на план запроса:Let's look at the query plan:
explain analyze
select *
from tst_join_types_int t1
join tst_join_types_int8 t2 using(id);
Gather Motion 864:1 (slice2; segments: 864) (cost=0.00..1002.34 rows=1000000 width=8) (actual time=150.920..339.981 rows=1000000 loops=1)
-> Hash Join (cost=0.00..975.58 rows=250000 width=8) (actual time=149.745..304.020 rows=250659 loops=1)
Hash Cond: (tst_join_types_int8.id = (tst_join_types_int.id)::bigint)
Extra Text: (seg2) Hash chain length 1.3 avg, 6 max, using 199357 of 524288 buckets.
-> Seq Scan on tst_join_types_int8 (cost=0.00..434.02 rows=250000 width=8) (actual time=0.243..36.083 rows=250659 loops=1)
-> Hash (cost=438.46..438.46 rows=250000 width=4) (actual time=149.033..149.033 rows=250659 loops=1)
-> Redistribute Motion 864:864 (slice1; segments: 864) (cost=0.00..438.46 rows=250000 width=4) (actual time=1.700..67.532 rows=250659 loops=1)
Hash Key: (tst_join_types_int.id)::bigint
-> Seq Scan on tst_join_types_int (cost=0.00..433.48 rows=250000 width=4) (actual time=0.548..51.956 rows=250659 loops=1)
Planning time: 9.074 ms
(slice0) Executor memory: 151K bytes.
(slice1) Executor memory: 220K bytes avg x 864 workers, 220K bytes max (seg0).
(slice2) Executor memory: 20840K bytes avg x 864 workers, 20840K bytes max (seg0). Work_mem: 5875K bytes max.
Memory used: 128000kB
Optimizer: Pivotal Optimizer (GPORCA)
Execution time: 399.750 ms
Как видим, первая таблица все равно перераспределилась по кластеру, хотя ключ ее распределения согласован с ключом второй табл-ы.
Но это еще не все. Оказывается, что сжатая zstd с int весит на 116% больше такой же с int8 ( см.фото ).
Выражаю признательность самому активному подписчику @GaRin_1979 за то, что подсветил феномен с размером int и int8 и поделился ссылкой , которая дала идею данному посту. Отдельный респект автору, который провел большое исследование и опубликовал его рез-т на хабре.
Хабр
Оптимизация Arenadata DB: как избежать критических ошибок и повысить производительность кластера
Привет, Хабр! Меня зовут Дмитрий Капралов, я работаю в команде консалтинга компании Arenadata. Одной из наших задач является проведение аудита кластеров СУБД Arenadata DB (ADB)....
👍7
image_2024-11-25_20-06-57.png
40.6 KB
по материалам based on https://habr.com/ru/companies/arenadata/articles/852830/