TGViewer
Channel Public Channel
DataДжунгли🌳

DataДжунгли🌳

@data_jungle

Data Engineering на пальцах:
🥸Про Airflow-DAG.
🍀ETL, с сарказмом.
🅾️оптимизируем SQL.
🐍Python трюки.
Subscribers
286
Photos
14
Videos
8
Links
30
Recent Posts 20 shown
Post #127 76
Мы уже проводим не первое интервью кандидатов на работе и вот что я могу посоветовать вам дорогие инженеры.
Как человек который послушал уже под 100 кандидатов что сразу отталкивает:

1. Если вы плохо говорите про свой опыт.
Просто готовьте пересказ заранее это же буквально на 5-7 минут. Часто начинают уходить в какие то тех детали которые не нужны, забывая вообще, про то зачем это бизнесу было надо, кто этим пользовался, как принимали решение, почему такой стек был. Вот эти вопросы важнее, дополнительно я сам найду что уточнить после спича вашего:)

2. Если кандидат говорит «а это не я делал, у нас там были девопсы» или кто то еще подобный. Зачем тогда в опыте написано “maintain self-hosted airflow” в этот момент я сразу задаю вопросы из чего состоял airflow, какой был executer и тд и тп. Но в ответ получаю «а это не я или не наша команда, а какие там эксекъютеры не помню и что такое шедулер и воркер».
Ребята «писал даг» и поддерживал селф хост airflow все таки задачки сильно разные 😁
Это вводит в смуту и сразу понимаешь что в CV какой то нейрослоп не полностью продуманный :) или не прочитанный:)

3. Лайв кодинг…. Это просто жесть 😬.
У нас задача 1 на питоне и там есть скрипт надо просто прочесть и понять какие там есть 3 неточности.
Если вы хотя бы год программировали простые какие то вещи это не проблема для вас.

И есть SQL 2 задачи даже 3 не помню когда давал.
Задача в SQL есть таблица А(1,1,1,3,5,null) и есть таблица Б(1,1,2,7,null)
Надо соединить всеми видами джоинов что вы знаете.
Я поражен что ребята с опытом типо в 7-10 лет не могу JOIN написать простейший…
Это буквально 70% отваливаются на лайв кодинга именно на JOIN:)
И это просто логическая задача :)


Я сам сейчас хожу на собесы тоже, расскажите какой у вас опыт вообще по поиску что спрашивали ?
Post #126 154
Неужели литкод это начало конца ?
Google сменил стратегию интервью:)
Что думаете обсудим ?
Post #125 217
Всем привет 👋
Очень советую посмотреть это видео на ютубчике.

Всегда с большим интересом наблюдаю как в долине люди мыслят :) тем более эксклюзив с с тем кто сделал макинтош.
Обязательно к просмотру

#DataJungle рекомендует.

https://youtu.be/_EnrAypg2Jk?si=BmXNpFuV1IvDhoVJ
YouTube Сооснователь Apple раскрыл ПРАВДУ о техногигантах Получите демо-доступ к 4dev - платформа для оформления и администрирования команды в любой стране мира: https://clck.su/kiHIb Зарядная станция Signature 3 в 1 и другие товары бренда Magssory со скидкой 20% по промокоду GITELMAN20: https://clck.ru/3VGwmN…
  • 👎 1
  • 🫡 1
Post #124 245
🔍 Как читать план запроса: EXPLAIN, оценки и почему оптимизатор врёт #SQLWednesday

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

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

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

Второе - план читается снизу вверх. Внизу источники данных, наверху результат.

И третье: смотреть надо всего на три вещи.

Где время. Не на весь запрос, а по операторам. Обычно 90% висит на одном, и это не то место, куда ты смотрел. Вот мой прогон на 5 млн транзакций, дедуп через ROW_NUMBER:

WINDOW 5,000,000 rows 3.51s
TABLE_SCAN 5,000,000 rows 0.06s

Чтение таблицы — шесть сотых секунды. Всё остальное время съела сортировка внутри оконной функции. Оптимизировать тут «чтение с диска» бессмысленно, лечится только раскладкой данных по ключу партиционирования.

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

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

Проверил на своей таблице. Условие status = 'refund', оптимизатор говорит:

SEQ_SCAN Filters: status='refund' ~2,500,000 rows

Два с половиной миллиона. По факту — 5029 строк. Ошибка в пятьсот раз, просто потому что статистики по этой колонке нет и движок честно поделил таблицу пополам.

Само по себе это не страшно, страшны последствия. На оценке в пять тысяч строк движок возьмёт nested loop и индекс. На оценке в два с половиной миллиона — построит хеш-таблицу и пойдёт сканом. Ошибся на входе - выбрал не тот алгоритм для всего дерева выше.
Так запрос, который вчера отрабатывал за две секунды, сегодня висит сорок минут, хотя ты в нём ничего не менял. - ! Менялись данные.

Отсюда типовые причины, почему оценки врут: статистика устарела после массовой заливки; в WHERE несколько условий, которые движок считает независимыми, а они жёстко связаны (город и почтовый индекс); на колонку навешана функция — DATE(created_at) = ... прячет от оптимизатора и статистику, и индекс; данные перекошены, и «средний» клиент существует только на бумаге.

Что с этим делать? : обновить статистику (ANALYZE в Postgres, UPDATE STATISTICS в SQL Server), убрать функции с колонок в предикатах, разбить монстра на шаги с материализацией, а не надеяться, что оптимизатор разрулит семиэтажный CTE.

И архитектурный угол. В лейкхаусе всё то же самое, только статистика живёт в метаданных: min/max по row groups в Parquet, счётчики в манифестах Iceberg. Поэтому Spark умеет adaptive query execution - начинает выполнять, видит реальные объёмы и на лету перестраивает план, потому что доверять оценкам на распределёнке уже никто не хочет.

Открываете план, когда что-то тормозит, или сразу лезете вешать индексы наугад? И какая была самая дикая разница между оценкой и фактом? 👇

#SQL #SQLWednesday #performance #ETL #DataJungle
  • 👍 2
Post #123 206
🧱 Parquet под капотом: почему «размер файла имеет значение»
Мы шли сверху вниз: разделили compute и storage → положили сверху Iceberg → разобрали каталоги. Остался последний этаж — сами файлы. Под каждым Iceberg лежит обычный Parquet, и именно здесь производительность или выигрывается, или проваливается.
🦖 Как было: строчный формат
CSV, Avro, любая OLTP-таблица хранят данные построчно. Чтобы посчитать SUM по одной колонке, движок физически читает строки целиком — все 200 полей. Для аналитики это катастрофа I/O: платишь за 200 колонок, используешь 3.
🟢 Как стало: колонки вместо строк
• Читаешь только нужные колонки (projection pushdown) — остальные с диска не поднимаются вообще.
• В колонке лежат однородные данные → сжатие в разы. Пять повторяющихся статусов в строке не сожмёшь, а в колонке они схлопываются в словарь.
🔬 Как устроен файл
файл → row groups (горизонтальные срезы, обычно ~128 МБ) → column chunks → pages.
В футере — схема и статистика по каждому chunk: min, max, число NULL.
И вот главное. Запрос WHERE created_at = ‘2026-07-20’: движок читает футер, видит по min/max, что в этом row group нужных дат нет, и пропускает его целиком — не читая ни байта данных. Это predicate pushdown.

🛠 Что это значит для DE
🔴 Мелкие файлы убивают. Миллион файлов по 10 КБ = миллион HTTP-запросов к S3, и платишь ты не за объём, а за latency каждого (привет посту про compute vs storage). Компакть в 128–512 МБ.
🔴 Несортированные данные = бесполезная статистика. Если ключ фильтрации размазан по всем row groups, min/max в каждом — «от января до декабря», и пропустить нельзя ничего. Сортируй перед записью по колонке, по которой реально фильтруешь: диапазоны станут узкими, и pruning начнёт резать.
🟡 Следи за размером row group и шириной схемы: слишком широкие и глубоко вложенные схемы бьют по памяти на запись, слишком мелкие row groups раздувают метаданные.
🟡 Партиционируй с умом (hidden partitioning в Iceberg), но не плоди тысячи мелких партиций — вернёшься ровно к проблеме №1.
🔮 А Parquet не устарел?
Формату больше десяти лет, и под ИИ-нагрузки он тесноват — точечный доступ к одной записи, фичестор на тысячи колонок, эмбеддинги.
На этом выросли Lance (быстрый random access и вектора),
Vortex (инкубируется в Linux Foundation) и
Nimble от Meta.
Но в 2026-ом: Parquet под управлением Iceberg остаётся источником правды для BI и всей классической аналитики, а новые форматы живут рядом, под ML. Переезжать всем пока не за чем.
🔗 Замыкаем цепочку
сеть (compute/storage) + колоночный формат (Parquet) + указатель каталога (Iceberg + REST) = весь Cloud-Native стек, который мы собирали четыре поста подряд.
Дальше — вверх, к движкам и стримингу.
Как боретесь с мелкими файлами — автокомпакция каталога (S3 Tables/Iceberg), OPTIMIZE, свой джоб? И сортируете ли данные перед записью? 👇

#data_engineering #parquet #lakehouse #storage #dj_architecture #DataJungle
  • ❤ 3
Post #122 163
🏝️ Gaps & Islands: как из потока событий собрать сессии одним оконным трюком #SQLWednesday

Задача, которая отделяет «пишу SQL» от «думаю окнами». Есть поток событий пользователя — надо склеить их в сессии (островки активности) и найти паузы между ними. На собесе спрашивают, а в проде это сессионизация, стрики и SLA-даунтаймы.

❓ Задача Таблица событий. Сессия = подряд идущие события одного юзера, где пауза между соседними ≤ 30 минут. Нужно вернуть: id сессии, начало, конец, число событий, длительность.

📋 Таблица и данные


CREATE TABLE events (
user_id BIGINT,
event_time TIMESTAMP
);
user_id | event_time | комментарий
1 | 2026-07-20 10:00 | сессия 1
1 | 2026-07-20 10:10 | сессия 1 (гэп 10 мин)
1 | 2026-07-20 10:25 | сессия 1 (гэп 15 мин)
1 | 2026-07-20 12:00 | пауза 95 мин -> сессия 2
1 | 2026-07-20 12:20 | сессия 2
2 | 2026-07-20 09:00 | Bob, сессия 1
2 | 2026-07-20 09:45 | пауза 45 мин -> сессия 2


🔴 Как НЕ надо Self-join «каждое событие с каждым», чтобы найти соседнее → O(n²). На миллионах событий встаёт колом.

🟢 Трюк Gaps & Islands — 3 шага

LAG(event_time) — берём время предыдущего события того же юзера.
Флаг новой сессии: если предыдущего нет ИЛИ разрыв > 30 мин → 1, иначе 0.
Кумулятивная SUM(флаг) OVER (... ORDER BY time) — это и есть номер сессии (island id). Дальше обычный GROUP BY.

WITH ordered AS (
SELECT user_id, event_time,
LAG(event_time) OVER (PARTITION BY user_id ORDER BY event_time) AS prev_time
FROM events
),
flagged AS (
SELECT user_id, event_time,
CASE WHEN prev_time IS NULL
OR event_time - prev_time > INTERVAL '30 minutes'
THEN 1 ELSE 0 END AS is_new
FROM ordered
),
sessions AS (
SELECT user_id, event_time,
SUM(is_new) OVER (PARTITION BY user_id ORDER BY event_time) AS session_id
FROM flagged
)
SELECT user_id, session_id,
MIN(event_time) AS session_start,
MAX(event_time) AS session_end,
COUNT(*) AS events,
date_diff('minute', MIN(event_time), MAX(event_time)) AS duration_min
FROM sessions
GROUP BY user_id, session_id
ORDER BY user_id, session_id;

⚙️ Через призму эффективности

Один проход + оконные функции вместо self-join. По сути один sort по (user_id, event_time).
В lakehouse: если данные уже отсортированы/партиционированы по этому ключу — движок пропускает сортировку. Приём один-в-один масштабируется в Spark/BigQuery.
В стриминге это вообще встроено: session window в Spark/Flink делает ровно это на лету.

🧩 Тот же приём — другие задачи

Найти паузы (gaps): те же prev_time, но фильтр «разрыв > 30 мин» → окна простоя.
Стрики «N дней подряд заходил»: island по разнице дат.
Аптайм/даунтайм сервиса по логам.

🔴 Ловушки

RANGE vs ROWS во фрейме: по умолчанию окно работает как RANGE. Для нумерации сессий это ок, но при равных event_time знай разницу.
Тай-брейк: два события в одну секунду → добавь второй ключ в ORDER BY (event_id), иначе порядок недетерминирован.
Часовые пояса: «30 минут» на timestamptz считай аккуратно.
Диалекты: Postgres/DuckDB — event_time - prev_time > interval '30 minutes'; в других — date_diff / timestampdiff по минутам.

Проверил на DuckDB: 7 событий двух юзеров → 4 сессии. У Alice(имя выдуманное 🙂 ) первая — 3 события / 25 мин, вторая — 2 / 20 мин. Паузы 95 и 45 мин ловятся тем же LAG.

Как режете сессии на проде — этим трюком, session_window в Spark/Flink, или отдаёте стриминг-движку? И какой порог берёте — 30 мин, 15? 👇

#SQL #SQLWednesday #window_functions #sessionization #DataJungle
  • 👍 3
Post #121 175
🧠➡️🗃️ Text-to-SQL и семантический слой: почему LLM не убил аналитика(хотя и сильно повлияло на рынок)

Мой тезис из поста про будущее: «1 Data-спец + LLM закроет весь цикл». Пора его уточнить. Есть место, где LLM красиво падает лицом в стол - когда его пускают напрямую к сырой схеме БД. Разбираемся, почему Text-to-SQL работает на демке и разваливается на проде.

🎬 Обещание вендоров
Пишешь «покажи выручку по регионам за Q2» → LLM генерит SQL → готово. На трёх таблицах магия работает, все в восторге.

🔴 Почему ломается на реальном DWH (это уже прозвали accuracy cliff)

LLM угадывает смысл данных по косвенным признакам — именам таблиц и колонок. Он не знает, что такое «активный клиент», какой из пяти столбцов revenue настоящий и где soft-delete. И вы можете хоть усраться с инструкцией - промптом это все не работает поверьте мне я пытался такую систему создать почти год.

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

Самое опасное: ошибка Text-to-SQL выглядит не как ошибка, а как правдоподобный НЕправильный ответ. Запрос отработал, цифра красивая - а join не тот. Глазами это не ловится.
Порядок величин: в бенчмарке dbt (2026) на «сложных» вопросах голый Text-to-SQL давал ~50–65% верных ответов. Почти половина - тихий брак. Это проверено лично мной это с воздуха цифры.

🟢 Что реально помогает - семантический слой
dbt Semantic Layer, Cube, LookML.
Метрики, сущности и связи описаны один раз и версионируются в git.
Дальше LLM обращается не к 200 сырым таблицам, а к метрике revenue - а слой сам разворачивает корректный SQL(из RAG памяти) с нужными джойнами и фильтрами.
Ключевая разница - слой детерминирован. Вопрос вне его области → ты получаешь ошибку, а не выдуманную цифру. В том же бенчмарке на вопросах «в области» слоя точность - 66-78%. Это уже сильно лучше но построение этой архитектуры это большой сложный пайплайн + надо его поддерживать решать проблемы улучшать ответы, делать тюн модели, авто расширять RAG память.
И вот эти все приседания стоят месяцев работы, кучи сгоревших токенов, времени специалиста а эффект как бы по прежнему не 100%.
При этом человек пописавший SELECTы придет с какой то доказательной базой к стейкхолдерам и докажет свою точку зрения на данных, LLM вы либо верите либо нет 😁 потому что ее доказательства они могут быть какими угодно - дабы угодить пользователю - то есть вам. Таков принцип этих моделей давать вам средневзвешанное наиболее подходящее.

🧰 Плюс паттерны grounding (пока слоя нет)

RAG по описаниям таблиц и бизнес-глоссарию;
few-shot из проверенных, «золотых» запросов;
LLM работает не по всей схеме, а по ограниченному набору вью;
«LLM предлагает - тесты/человек подтверждают», а не «LLM сразу в прод».

🛠 Мой взгляд - что это значит для DE и других DATA специалистов.
LLM сдвигает работу не в «писать меньше SQL», а в «строить семантику и контракты, на которые модель может опереться». Инженер данных = тот, кто делает данные понятными для машины: чистые метрики, документированные сущности, governance. Это и есть та самая «база» из прошлых постов - архитектура важнее синтаксиса.
И это лищь продолжение поста(мысли) про каталоги: семантический слой + governance — ровно то, без чего нельзя пускать к данным ни аналитика-LLM, ни автономного агента.

Есть еще один слой в этом посте который я давно уже заметил. Ваш ИИ помошник - настолько же умен, насколько умны вы 😎. Я расскрою тему вам в следующем посте по теме ИИшных дел.

Пробовали Text-to-SQL на проде? Взлетело или тихо врало? И строите ли семантический слой — dbt, Cube, LookML, своё? 👇

#data_engineering #AI #LLM #text2sql #semantic_layer #DataJungle
  • 🔥 1
Post #120 158
Решил поделиться некоторыми мыслями касательно KPI, которыми так любят обкладывать нашу работу.

В моей компании лишь недавно руководству стало интересно
«А че тут ваще все делают» и дабы объяснить в каких то цифровых выражениях работу творческих личностей типо меня, тут же откуда то берутся метрики которые ваш покорный слуга всегда считал началом конца 😁

Да наверное среди менеджеров были допущены некоторые ошибки, которые привели к потерям и в маркетинге возможно тоже, но кто мне скажет об этом явно:)
Я лишь могу поселектить чуть 🤏 и сделать некоторые выводы.

Как правило «нам нужны метрики для оценки вашей работы» сопровождается еще и увольнениями старой гвардии в компании.
Типо они давно работали и возможно их пыл угас и им не так хочется зарабатывать деньги для компании а хочется просто жить, растить детей и путешествовать. Они же настроили все процессы и создали команды. Но для компании как правило такой сотрудник уже не особо нужен.
Я это заметил уже не в одной компании и процесс всегда одинаковый когда начинается перестройка.

Я понимаю что бизнесу надо все померить и посчитать.
И надо это лишь в одном случае - убедится что ты не мало работаешь и перформишь 😁

На мой вопрос а что если я согласно вашей же метрики сильно лучше делаю, вам надо 80% а я делаю 110%. Отразится это на мне положительно ? Может выходной дополнительный, может вымпел, медаль, грамота?
Про деньги говорить вообще бессмысленно 😁
Ответ компании - нет. А вот если я буду давать не 110% стабильных процентов а только 80% требуемых:) то это быстро заметят.

Щас самые умные из вас скажут а зачем делать больше если никто не просит :)

А я жил и не знал что я столько делаю метрик то не было. А теперь есть.


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

Снизить перфоманс? Или оставаться собой и будь что будет?
Как бы вы поступили ?

Все персонажи вымышлены.

#мысливслух
  • ❤ 5
Post #119 189
🗂️ Война каталогов Iceberg: Glue vs Polaris vs Unity vs Nessie - кто держит указатель
#dj_architecture

В посте про Iceberg я закончил вопросом «на каком каталоге сидите?». Ответов от вас не последовало ибо вы походу и не знает что это 🙂
🦖 Быстрое напоминание
Iceberg - это метаданные поверх обычных Parquet. Любая запись = новый metadata.json + атомарная подмена указателя на текущий. Так вот тот, кто хранит этот указатель и атомарно его переключает, и есть каталог. Без него нет ни ACID, ни single source of truth: два движка просто затрут друг друга.

🔑 Почему всё крутится вокруг REST-каталога
Ключевая вещь последних лет - Iceberg REST Catalog spec. Это один HTTP-контракт: движок пишет REST-клиент один раз, каталог — REST-сервер один раз, и дальше все со всеми.
Раньше под каждую пару движок ↔ каталог пилили отдельную интеграцию. Теперь нет. Вот это и есть настоящая смерть vendor lock-in - но уже на уровне метаданных, а не файлов.

⚔️ Игроки (честно, с их дырами)
🟢 Apache Polaris - дорос до top-level проекта Apache, де-факто community-стандарт REST-каталога. Open source + managed-вариант от Snowflake.
🟡 AWS Glue - родной для экосистемы AWS, но REST-полнота хромает (нет UpdateTable, пробелы в v3).
🟢 AWS S3 Tables - Iceberg как first-class ресурс прямо в S3: v3, автокомпакция, высокий tx-rate. По сути managed-каталог из коробки для тех, кто на AWS.
🟡 Unity Catalog (OSS) — Databricks открыли исходники, но он Delta-first: поддержка Iceberg догоняет, gap до managed-версии реальный. Логичен, если живёшь в Databricks.
🔵 Nessie - git-like ветки и теги для метаданных: эксперимент на ветке, мерж как в git. Data CI/CD. Минус - нужен внешний слой авторизации.
🔵 Lakekeeper - лёгкий бинарь на Rust, сильная авторизация (OpenFGA/OPA), k8s-native. Молодой, но интересный, если своё облако и жёсткий RBAC.
⚫ Hive Metastore - легаси на Thrift. Не выбор для нового, а то, с чего мигрируют в день, когда переросли.

Честно я сам половину слов не знаю накопал с помощью ИИ в интернетах для обощревания просто.

🛠 Что это значит для DE

Каталог - это не служебная деталь, а точка governance: кто видит таблицу, кто пишет, как разрулить конкурентную запись.
Выбор по-простому:
весь в AWS без Databricks → S3 Tables / Glue;
хочешь вендор-нейтральный стандарт → Polaris;
нужен git-workflow на данных → Nessie;
своё k8s + жёсткий доступ → Lakekeeper;
в Databricks → Unity.

Правило простое: данные держи в открытом формате (Iceberg на S3), а каталог выбирай так, чтобы в любой момент переключить движок и не переезжать. Lock-in теперь прячется именно в каталоге, а не в формате.

🔮 Мостик к будущему что мне действительно нравится.
Формат-война кончилась, и весь фронт сместился на каталог. Именно он теперь решает не только кто читает таблицу, но и governance для волны ИИ-агентов, которые сами ходят в данные. Каталог = кто и что имеет право сделать с данными: хоть человек, хоть агент.

На каком каталоге сидите в проде — и почему ушли (или наоборот не уходите) с Glue/Hive? 👇

#data_engineering #iceberg #lakehouse #catalog #DataJungle
  • 🔥 1
Post #118 208
Прям статья какя то а не номер сессии :)
Post #117 210
🗄️ Последняя транзакция каждого клиента: одна задача с собеса - три решения #SQLWednesday - и не важно что сегодня не среда.

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

❓ Задача
Есть таблица транзакций. Нужно вернуть последнюю по времени транзакцию каждого клиента(успешную или нет не важно) - целиком, со всеми полями, а не только max(время). top-1 на группу (greatest-N-per-group).

табличка транзакций

CREATE TABLE Transactions (
id BIGINT PRIMARY KEY, -- id транзакции
customer_id BIGINT, -- клиент
amount DECIMAL(12,2), -- сумма
status VARCHAR, -- статус
created_at TIMESTAMP -- время транзакции
);

Пример данных

id | customer | amount | status | created_at
101 | 1 | 50.00 | done | 2026-07-01 10:00
102 | 1 | 75.00 | done | 2026-07-10 14:30
201 | 2 | 20.00 | done | 2026-07-05 09:00
202 | 2 | 30.00 | failed | 2026-07-15 09:00
203 | 2 | 30.00 | done | 2026-07-15 09:00
301 | 3 | 100.00 | done | 2026-07-12 12:00

Итак какие у нас варианты решений - да их больше чем 1:

1) Коррелированный подзапрос. Просто в лоб и напрашивается само.

SELECT t.*
FROM Transactions t
WHERE t.created_at = (
SELECT MAX(t2.created_at)
FROM Transactions t2
WHERE t2.customer_id = t.customer_id
);


Да работает, но:
• На каждую строку лезет в подзапрос за MAX (оптимизатор иногда перепишет, иногда нет);
• БАГ: у customer_id=2 две транзакции с равным created_at → вернутся ОБЕ. Должно быть 3 строки а будет 4. Придется думать над доп фильтром;

2) Оконная функция ROW_NUMBER() - конечно же.

WITH ranked AS (
SELECT t.*,
ROW_NUMBER() OVER (
PARTITION BY customer_id
ORDER BY created_at DESC, id DESC
) AS rn
FROM Transactions t
)
SELECT * FROM ranked WHERE rn = 1;


Почему это стандарт для подобных задач?:
• один проход по таблице;
• тай-брейк вторым ключом (id DESC) - детерминированно одна строка, бага с дублями нет;

⚡️ ROW_NUMBER, а не RANK — RANK при равных значениях вернёт дубли.

Но есть ли еще что то ? Еще более быстро и красиво?
Знакомьтес с мистером LATERALL и CROSS APPLY

3) LATERAL (Postgres) / CROSS APPLY (Sql Server)


— Postgres
SELECT t.*
FROM Customers c
CROSS JOIN LATERAL (
SELECT *
FROM Transactions t
WHERE t.customer_id = c.customer_id
ORDER BY t.created_at DESC, t.id DESC
LIMIT 1
) t;

— Sql Server
SELECT t.*
FROM Customers c
CROSS APPLY (
SELECT TOP 1 *
FROM Transactions t
WHERE t.customer_id = c.customer_id
ORDER BY t.created_at DESC, t.id DESC
) t;

🟢Фишка этого решения - при индексе (customer_id, created_at DESC) движок делает index seek на каждую группу - это почти O(числа клиентов), а не сортировка всей таблицы.

CREATE INDEX ix_txn ON Transactions (customer_id, created_at DESC, id DESC);

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

⚖️ Что выбрать - через призму архитектуры
• Классическая OLTP-СУБД с индексом (Postgres / SQL Server) → LATERAL / APPLY обычно быстрее: seek по индексу вместо полной сортировки.
• Колоночный движок / lakehouse (BigQuery, Snowflake, Spark, Iceberg + Trino) → индексов нет, зато дёшево сканировать и сортировать колонки → выигрывает ROW_NUMBER, и он отлично параллелится.
• Коррелированный подзапрос → ответ уровня а как ещё можно - не более :).

🔴 Ловушки, на которых валят
• RANK вместо ROW_NUMBER = дубли при равных ключах.
• Нет тай-брейка (id) в ORDER BY → результат недетерминирован, на равном времени каждый раз может быть разная строка.
• NULL в created_at: при ORDER BY ... DESC в Postgres NULL уезжает наверх (NULLS FIRST) и притворяется «последним». Пиши NULLS LAST.
• Нужны и клиенты без транзакций? Подзапрос и оконка их не вернут — бери LEFT JOIN LATERAL.

#SQL #window_functions #ETL #DataJungle
  • 🔥 3
Post #115 202
Рубрика #НАВАЙБКОЖЕНО
🤖 Я собрал ИИ-агента, который сам торгует криптой ончейн. Разбираю архитектуру

В посте «Я вернулся» обещал показать ИИ-агента для торговли: разбираю для вас архитектуру рабочей системы.
Это Telegram-бот, который сам находит сигнал, сам исполняет своп в блокчейне и сам отчитывается. Человек в цикле — только чтобы нажать «Старт».
Спойлер - денег не принесло 🙂 но и особо не потеряло 🙂

🦖 Как выглядит «бот-трейдер» обычно
API-ключи к бирже + скрипт по расписанию, который дёргает REST и ставит ордера. Деньги лежат на бирже (кастодиально), ключи — вечная головная боль по безопасности. И «агентность» тут фейковая: это cron, а не агент.
Я хотел иначе: агент с собственным некастодиальным кошельком, который действует ончейн сам. А LLM - это слой оркестрации и объяснения решений, а не оракул, который «чувствует» цену. LLM выполняла контракт но не принимала решение как таковое, данные были реальные с биржи.

🧩 Архитектура по слоям
Bot Layer — aiogram 3.x (async). Команды /start, /wallet, /portfolio, /strategy, /mode, /pause. Витрина — Telegram Mini App на React 18 + Vite + Tailwind.
Agent Layer — здесь ИИ. Coinbase AgentKit + LangChain + Claude.
Cигналы считаются детерминированно, а не нейронка угадывает рынок.

Signal analyzer: RSI(14), volume ratio (объём против 7-дневного среднего), тренд по кроссу EMA20/EMA50. Данные — CoinGecko/DexScreener.
Правило buy-сигнала: RSI < 35 И volume_ratio > 1.3 И trend = bullish → сделка с confidence-скором.
Trade executor: агенту прилетает промпт «Swap {amount} {token_in} for {token_out}», и AgentKit исполняет своп на Uniswap/Aerodrome.
Роль LLM/агента — превратить решение стратегии в безопасное ончейн-действие. Не предсказание, а исполнение.

On-chain — Coinbase CDP, сеть base-mainnet. На каждого юзера создаётся некастодиальный CDP-кошелёк: приватный ключ живёт в TEE у Coinbase, у меня его нет. Это убивает самый страшный риск бота — «слили ключи, увели депозит». Своп реально уходит в блокчейн и возвращает tx_hash — всё аудируемо.

Data Layer — PostgreSQL + SQLAlchemy (async) + Alembic. Таблицы: users, wallets (cdp_wallet_id + Base-адрес), trades (сигнал + P&L + tx_hash), portfolio_snapshots, notifications_log.

Scheduler — APScheduler.
Тут вся «жизнь» агента:
market monitor — каждые 5 мин анализ сигналов;
risk manager — каждую минуту проверяет стопы;
snapshot портфеля — раз в час;
daily report — в 9:00.

🛡️ Риск-менеджмент (без него это казино)
Demo-режим по умолчанию: виртуальная $1000 USDC. Боевой режим включаешь сам.
Три профиля — conservative / balanced / aggressive: размер позиции 5–20%, стоп −5…−12%, тейк +8…+25%, вайтлист токенов.
Глобальные предохранители: дневной убыток больше 15% → агент встаёт; макс. слиппедж 2%; не торгует при балансе меньше $10.
Demo и боевые сделки жёстко разделены в БД и в UI (бейдж WHAT IF) — чтобы не путать «как бы» и реальные деньги.

🛠 Что это значит для DE
«ИИ-агент» на проде - это на 80% обычная дата-инженерия: сбор данных, фиче-инжиниринг (RSI/EMA/объёмы), стейт в Postgres, шедулер, идемпотентность, аудит. LLM - тонкий слой сверху, а не вся система.
Самое сложное не модель сама все делает, а надёжность: упал провайдер данных на середине цикла; как не исполнить своп дважды; как держать портфель консистентным. Те же вопросы, что и в любом ETL - только цена бага живые деньги.
AgentKit и x402 из прошлого поста тут перестают быть теорией: кошелёк агента + автономное ончейн-действие = «машина торгует сама». И это буквально тезис «1 Data-спец + LLM»: один человек закрыл данные, стратегию, бэкенд, исполнение и фронт.

⚖️ Осторожно
Это не печатная машинка денег. Бэктест ≠ будущее, рынок меняет режим — любой ТА однажды ломается. Поэтому demo-first, лимиты и circuit breaker — не украшение, а условие запуска. Автономный агент с реальным кошельком = новый класс рисков: баг исполняется реальным свопом. Ничего из этого не инвест-совет.

РЕПОЗИТОРИЙ ОТКРЫТ
Только для моих верных подписчиков - там более чем все подробно отдавайте вашему ИИ и может у вас выйдет то что не вышло у меня 🙂 делитесь в коментах что думаете.
GitHub GitHub - da-eos/tryscout_ai Contribute to da-eos/tryscout_ai development by creating an account on GitHub.
  • ❤ 1
  • 🔥 1
Post #113 387
⚡️ Apache Iceberg: ACID на S3 и конец vendor lock-in 🧊

В прошлом посте разобрал, почему compute уехал отдельно от storage. Остался висящий хвост: данные в S3, а как там делать UPDATE, откатить кривой DAG, поменять схему без перезаливки 50 ТБ?
В DWH за это отвечала база. В озере на S3 — никто. До Iceberg.

🦖 Жизнь до этого: Hive
Hive table format = «папка в S3 это таблица, подпапки — партиции». Метаданные — только список путей.

Что не так:🔴

• Никакого ACID. Пайплайн упал на середине — читатели видят битые данные.
• Schema evolution через боль. Поменять тип колонки = переписать таблицу.
• Партиции зашиты в путь. Сменить схему партиционирования — перезаливай всё.
• Planner делает LIST по S3. На миллионе партиций умирает.
• UPDATE/DELETE нет. GDPR-удаление = читай партицию, фильтруй, перезаписывай.

☁️ Что сделал Iceberg

Не движок и не сторадж. Спецификация метаданных поверх обычных Parquet.
Слои:
- Каталог (Glue/Polaris/Unity/Nessie) — указатель на текущий metadata.json.
- metadata.json — схема, партиции, список снапшотов.
- Manifest list → manifest → data files (Parquet) со статистикой по колонкам.

Любая запись = новый metadata.json + атомарная замена указателя в каталоге. Старые файлы остаются. На этом построено всё:

🟢 ACID. Запись видна целиком или не видна. Конкуренция разруливается через optimistic concurrency на уровне каталога.
🟢 Time travel. SELECT ... FOR VERSION AS OF 12345. Откат на снапшот без бэкапов.
🟢 Schema evolution. Колонки идентифицируются по ID, переименование/смена типа — правка metadata.json, данные не трогаются.
🟢 Hidden partitioning. Партиции в метаданных. Меняешь day → hour через ALTER, старые данные не переписываешь.
🟢 Pruning без LIST. Planner читает manifest и сразу знает нужные файлы.
🟢 Branching/tagging как в git.

🛠 Что это значит для DE

Vendor lock-in мёртв. Один датасет в S3 одновременно читают Snowflake, Databricks, Trino, DuckDB, BigQuery — и видят одно и то же.
Война форматов закончилась. Snowflake купил Tabular, Databricks open-source-нул Unity Catalog, AWS выкатил S3 Tables (это Iceberg под капотом).
Индустрия сошлась на одном формате впервые за 15 лет.

⚖️ Где не подходит

• OLTP не закроет: каждая запись = коммит в каталог, это десятки миллисекунд. Частые мелкие апдейты убьют через write amplification.

Iceberg для аналитики, истории, ML-фич, маркетов — то есть 80% работы DE.
Используете в проде? На каком каталоге — Glue, Unity, Polaris, своё? Делитесь в комментах 👇

#data_engineering #iceberg #lakehouse #s3 #dj_architecture #DataJungle
  • 👍 4
  • ❤ 3
  • 🔥 2
Post #112 374
Вот книга про которую пишу, всем инженерам рекомендую к прочтению 1️⃣0️⃣0️⃣🔤
  • ❤ 3
Post #111 308
Инженерия данных - это всё ещё про написание кода или уже про настройку - а вот чего настраивать ? 😎

Недавно зарылся в финальную, 11-ю главу «Основ инженерии данных» Риса и Хоусли.
Авторы пытаются заглянуть за горизонт и понять, куда мы все катимся.

Что там пишут? 🤯 - издание от 2022 года если что 🤖
• Инструменты упрощаются.
• Эпоха, когда нужно было быть «хакером инфраструктуры», чтобы просто заставить данные течь из пункта А в пункт Б, уходит.
• Наступает эра Cloud Data OS, где всё работает из коробки, а фокус смещается с как это поднять на как это приносит пользу бизнесу(FinOps).
• Стриминг вытеснет батчи.

+ Ещё пророчат окончательное слияние инженерии данных с разработкой приложений и ML.
То есть инженер данных будущего - это не просто парень - ETL-пайплайн, а полноценный архитектор систем, где данные и логика неразрывны.
В целом то мы никогда не были "Просто парнем с ETL" 👀

В чем авторы оказались чертовски правы? 🔤

Прошло почти 4 года с момента выхода оригинала, и вот что из предсказаний стало нашей реальностью:
• Инструменты для людей (User-Friendly Infrastructure): Посмотрите на расцвет стека вокруг dbt, Airbyte или managed-решений в облаках. Настройка базового пайплайна теперь занимает часы, а не недели. Порог входа в железо действительно упал.
• Инженер данных <-> Backend-разработчик: Грань стирается. Мы всё чаще пишем на Python/Go, используем CI/CD, тесты и программные паттерны. Больше нет просто SQL-парней, есть разработчики платформ данных.
• Real-time - это база: Если в 2022-м потоковая обработка была космосом для избранных, то сегодня бизнес требует отчеты здесь и сейчас. Kafka, ClickHouse и стриминг стали стандартом де-факто для живых систем.
• Фокус на FinOps: Как и предсказывали авторы, умение не просто поднять кластер, а сделать это эффективно и не раздеть компанию на счетах от AWS/GCP - это теперь чуть ли не ключевой скилл сеньора.

Мой взгляд на джунгли данных сегодня:

1. Бизнес-эффект- это фильтр №1. Построить эффективную платформу, где ясно, как данные превращаются в решения - это база.
Если нет понимания бизнес-эффекта от датасета, мы такое в работу... ну, в идеале не берем (хотя, признаюсь, грешим иногда, берем 😄). Но стратегически - DE без понимания бизнеса больше не живет.
2. Стриминг перестал быть болью. Технологии типа Pub/Sub - это теперь супер-удобно. Легко поднимается, масштабируется, а мониторинг не превращается в ночной кошмар.
3. Грани между DE и Backend никогда и не было. Для меня всегда было нормой: сам разработал сервис, сам поднял, сам встроил в архитектуру и сам поддерживаешь. Будь то кастомный код или Open Source вроде Airflow и Superset. Ты - инженер в широком смысле, а не просто перекладыватель json-ов.
4. ML - это просто часть пайплайна. Имплементация моделей в логику, настройка входов/выходов и дообучение — это задачи, которые DE-специалисту(мне) приходится решать постоянно.
5. FinOps - бесконечная история. Облака и их стоимость - это отдельное искусство, которое я сам продолжаю осваивать. Это критически важный навык: сделать не просто работающее решение, а экономически оправданное.

Какое будущее? 🔮
Мой вывод: скоро формула будет выглядеть так: 1 Data-спец + LLM.

Один человек с помощью ИИ сможет закрыть весь цикл:
✅ Глубокий анализ.
✅ Создание ML-модели.
✅ Написание бэкенда.
✅ Деплой и настройка CI/CD.

В итоге мы получаем не просто инженера данных, а Full-stack Data Product Engineer - человека, который в одиночку выдает готовый продукт, полностью закрывающий потребность бизнеса.

Согласны с таким прогнозом или DE останется узкой нишей? Пишите в комментариях! 👇

#data_engineering #future #books #DataJungle
  • 🔥 3
Post #110 270
⚡️Separation of Compute and Storage: Почему все уезжают в облако и как это работает на уровне железа?

Прямо сейчас на моей работе мы с командой ДЕ переносим наш SQL Server в BigQuery. Не буквально конечно :).
Это не просто смена вендора. Это переход на фундаментально другую архитектуру работы с данными с онпрем сервера(ов) на распределенное облако.

Что такого в облаках стоящего? Помимо того что навязывает маркетинг.

🦖 Эпоха HDFS и Data Locality
Раньше был Hadoop и классические СУБД (тот же SQL Server на железе). Архитектура строилась на принципе Shared-Nothing и Data Locality: данные лежат на тех же серверах, которые их обрабатывают.

Проблема очевидная: Вычисления (CPU/RAM) и диски масштабируются неравномерно. У вас копятся петабайты исторических логов? Будьте добры докупить серверы, переплачивая за мощные процессоры, которые будут просто простаивать.

☁️Эпоха Cloud-Native
Современные базы (BigQuery, Snowflake, ClickHouse Cloud) и Data Lakes работают иначе. Данные навсегда отрываются от серверов и уезжают в Объектное хранилище (S3 / GCS).
А серверы вычислений (Compute nodes) живут отдельно и поднимаются по клику.

Но тут возникает главная архитектурная проблема: Физика объектных хранилищ.
S3 — это не файловая система. Это гигантский распределенный Key-Value сторадж, с которым мы общаемся по HTTP-протоколу. И у него есть две важнейшие характеристики, которые дата-инженер обязан понимать:
🔴 Ужасная задержка (Latency): Время до получения первого байта (TTFB) из S3 измеряется десятками миллисекунд. Для базы данных это вечность. Локальный SSD отдал бы данные в тысячи раз быстрее. Если ваша база будет читать из S3 мелкие файлы в один поток — она умрет.
Но!
🟢 Бесконечная пропускная способность (Throughput): В отличие от жесткого диска, который упирается в интерфейс SATA/PCIe, S3 позволяет скачивать тысячи файлов одновременно. Вы можете поднять 1000 серверов, и каждый скачает свой кусок на скорости 10 Гбит/с.

🛠 Как современные движки обходят физику?
Если S3 такой медленный на старт, почему BigQuery или Snowflake отдают аналитику за секунды?
Кэширование на локальных NVMe-дисках.
Вычислительные узлы (Compute) в облаке все равно имеют свои сверхбыстрые диски. Но они больше не используются как Primary Storage. Теперь это просто эфемерный кэш.
Как выглядит жизненный цикл запроса:
Вы пишете SELECT.
- Оптимизатор делит запрос на тысячи мелких тасок.
- Движок смотрит: есть ли нужные колонки в оперативной памяти?
Если нет — лезет на локальный NVMe SSD(горячие данные, которые читали недавно).

Если и там нет — идет в S3 (холодные данные), но делает это агрессивно и параллельно, выкачивая гигантские блоки данных большими кусками, чтобы перекрыть высокую сетевую задержку огромным Throughput'ом.

Что это значит для дата-инженера?
Размер файла имеет значение. Миллион мелких файлов по 10 КБ в S3 убьют любой движок из-за Latency на каждый HTTP-запрос.
Локальные джойны в памяти уходят в прошлое.
Теперь узкое горлышко вашей архитектуры — это пропускная способность сети внутри дата-центра.
Мы уходим от оптимизации индексов на жестких дисках к оптимизации сетевого I/O и колоночных форматов.
Добро пожаловать в Cloud-Native!

Волшебной таблетки нет.
Нужно держать 10,000 транзакций в секунду с миллисекундным откликом (OLTP)? Берем классическую архитектуру с тесной связкой CPU и SSD.
Нужно сканировать терабайты данных, отдавать их разным командам и не разориться (OLAP/Data Lake)? Уходим в Cloud-Native форматы с разделением стораджа и вычислений.

#data_engineering #cloud_native #bigquery #olap #oltp
#dj_architecture
  • 🔥 6
Post #109 290
Я вернулся, или Почему в Data Jungle была тишина 🌿

Всем привет! С октября от меня не было ни звука. Пришло время объясниться. 🙈
Честно? Я ушел в глубокий «режим выживания» и «стройки». Пока индустрия гудела, а ИИ начал стремительно наступать на пятки и (давайте будем честны) пытаться откусить кусок нашего хлеба, я решил не паниковать, а адаптироваться. Все эти месяцы я с головой ушел в свои проекты. Коих накопилось немало:

1️⃣ Автоматизированная крипто-торговля (фьючерсы).
Мы с другом-трейдером объединили опыт, чтобы автоматизировать стратегию высокочастотной торговли (анализ ежеминутный). Немало копий было сломано и денег потеряно, но бэк-тесты за несколько лет показывают более 200% PnL в год (на 1-е плечо!). Сейчас идет тест на реальном небольшом депозите — и пока всё идет по плану(в +). 📈 Это не «прогрев» аудитории и проект не будет публичным, просто хочу показать: если эксперты вкладывают душу, цифры говорят сами за себя.
2️⃣Преподавание.
Участвую в благотворительном проекте: обучаю детей SQL. Прививаю им «любовь» к базам данных, чтобы не только мы одни страдали, как говорится! 😈📊
3️⃣ ИИ-агент для торговли.
Новый проект по автоматизации через ИИ-агентов. Оказалось, что у Coinbase есть протокол, где ИИ-агент может совершать сделки прямо в блокчейне! Ты просто пишешь ему: «Купи ETH за USDC» — и всё происходит автоматически. Сам не верил, пока не попробовал. Скоро дам вам протестировать! 🤖🔗 а вот это маленький прогрев :)

Что я понял за это время? 💡

Писать вам про банальные Python-трюки стало бессмысленно. Есть нейронки, которые делают это за вас и зачастую куда изящнее. 🐍➡️🤖
Я уверен на 100%: сейчас критически важно качать архитектурное мышление и понимание низкоуровневых процессов. Умение писать код — это теперь база, а вот умение проектировать системы, которые работают эффективно и масштабируемо — это скилл будущего тем более в дата отрасли. Читал на Хабре что спрос на Дата профессии сочетающие в себе + DevOPs роль выросли на 300%. Если вы специалист в дата области + умеете в серверной части многое - поверьте вы очень нужны рынку.

Поэтому меняю вектор канала: я продолжу делиться тем, что реально важно, и возобновлю разбор задач с собеседований, но уже под другим углом — через призму архитектуры и эффективности.
В следующем посте расскажу подробнее про ИИ-агента для торговли. Не переключайтесь! 🚀

#DataJungle #DataScience #AI #MachineLearning #PersonalProjects #BackToWork #SoftwareArchitecture
  • ❤ 9
  • 👍 3
  • 👎 1
  • 🔥 1
Post #108 523
Поиск отличий между таблицами («дифф»)

#SQLWednesday

👯‍♂️ Две таблицы заходят в бар… и нужно понять, чем они отличаются.
Классика собесов - сравнить два снапшота данных.


Есть таблицы:
• Customers_2024
• Customers_2025

Нужно:
1. Кто появился новым?
2. Кто удалился?
3. У кого изменились данные?


-- Новые клиенты (есть в 2025, нет в 2024)
SELECT c2025.id, c2025.name
FROM Customers_2025 c2025
LEFT JOIN Customers_2024 c2024 ON c2024.id = c2025.id
WHERE c2024.id IS NULL;

-- Удалённые клиенты (были, но пропали)
SELECT c2024.id, c2024.name
FROM Customers_2024 c2024
LEFT JOIN Customers_2025 c2025 ON c2025.id = c2024.id
WHERE c2025.id IS NULL;

-- Изменения в данных (id совпал, поля разные)
SELECT c2024.id,
c2024.name AS old_name,
c2025.name AS new_name
FROM Customers_2024 c2024
JOIN Customers_2025 c2025 ON c2025.id = c2024.id
WHERE c2024.name <> c2025.name; -- вот тут будет ошибка если NULL поэтому будьте аккуратны


Что тут важно:
• JOIN-ы вместо минусов - так быстрее и прозрачнее.
• Для сравнения всех полей можно собрать CHECKSUM(*) или HASHBYTES (SQL Server) / md5(row::text) (Postgres).
• Не забудьте про NULL: <> не работает, используйте IS DISTINCT FROM (Postgres) или EXCEPT для простого диффа.

Конечно все это уже давно решается с помощью SCD но это задача с собеседований на DE не редкость.

🔥 Такой «diff» помогает искать не только ошибки загрузки, но и баги в ETL, поэтому это валидно и для анализа и для DE.

#SQL #DataDiff #ETL #DataJungle
  • 🔥 7
  • 👍 1
Older posts →

About this channel

How can I read @data_jungle without a Telegram account?
TGViewer shows the public web preview Telegram publishes for DataДжунгли🌳: recent posts, photos, videos and the subscriber count, with no app, login or account.
How many subscribers does DataДжунгли🌳 have?
DataДжунгли🌳 (@data_jungle) has 286 subscribers on Telegram, refreshed roughly every 30 minutes.
Does DataДжунгли🌳 know I viewed it here?
No. Public channel previews carry no viewer identity, and TGViewer has no accounts or tracking of what you look up.
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →