дата инженеретта – Telegram
дата инженеретта
2.98K subscribers
242 photos
28 videos
3 files
101 links
мелкое — крупно,
в глубоком разговоре
мудрость приходит

по вопросам сюда: @aigul_sea
Download Telegram
Управляем ошибками. Часть 2

📼 Late Data

Посмотрим на 3 паттерна для работы с данными, которые пришли позже, чем ожидалось

1️⃣Pattern: Late Data Detector

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

Интересная мысль - "shifting the late data problem"
Пример: мы пишем партиции по времени обработки. В партицию 21:00 к нам залетел кусок данных за 20:00 и 19:00. А наши пользователи используют партиции по времени события. Тогда мы перекладываем ответственность ковыряться в этих партициях на них 😁

2️⃣Pattern: Static Late Data Integrator

Как вообще можно перегрузить данные за прошлое?

1. Создать кучу дагранов, где каждый перегружает 1 день. Если упало - перезапускаем конкретный день

2. Создать один дагран, где в коде генерируется список нужных дат. И по каждой дате запускается загрузка. Если упало - просто перезапускаем, пойдет считаться с упавшего дня. Это и есть Static Late Data Integrator. А статическое - потому что мы сами задаем 14 дней или сколько угодно

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

1. Задаем стартовую и конечную даты расчета
2. Создаем диапазон значений


full_range = pd.date_range(start=str(start_dt), end=str(end_dt)).strftime("%Y-%m-%d")


3. Из меты достаем существующие партиции


def get_existing_partitions(table_name):
partitions = (
spark.sql(f"show partitions {table_name}")
.select(F.split(F.col("partition"), "=")[1].alias("dt"))
.collect()
)

return [p[0] for p in partitions]


4. Находим разницу


lost_range = full_range.difference(existing_partitions_pdf)


5. Итерируемся по потеряшкам


for dt in lost_range:
calc_mart(dt)


Если в будущем снова будет пустая дата, нам не придется перезапускать определенный день - он пойдет считаться сам

3️⃣Pattern: Dynamic Late Data Integrator

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

Так мы запросом можем найти партиции, которые уже обрабатывались, но в которые попали новые данные. А в iceberg есть удобное свойство last_updated_at на уровне таблицы

🤩 Filtering

Pattern: Filter Interceptor

Как будто это антипаттерн. Предлагается создать доп колонки с фильтрами id_is_not_null, status_is_not_failed и выводить количество отфильтрованных записей, чтобы понимать, на каком этапе ошибка в коде или в данных. Но прям пробегаться по каждой записи в датафрейме… Как будто это все-таки dq

🌳 Fault Tolerance

Pattern: Checkpointer


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

Еще раз напомнили про семантики доставки:
🤩exactly once - нужны другие паттерны, расскажу, когда дойду
🤩at least once - чекпоинт после обработки, могут быть дубликаты при перезапуске после падения
🤩at most once - чекпоинт до обработки, данные потеряются при падении

#depatterns
Please open Telegram to view this post
VIEW IN TELEGRAM
10👍7🤔1
Мои заметки

У меня скопилось много заметок с митапов, из книг и разговоров. Я решила все собрать в один пост, а у себя почистить) Это будут просто рандомные мысли, которые меня зацепили, и иногда пояснения контекста. Разделила по категориям, чтобы это был порядочный хаос

Про жизнь

🟡Никто не обязан знать все и быть всегда правым
🟡В большинстве случаев все решаемо

Про работу

🟣На груминге задачи: «Мы не знаем, как это сделать, но надо как-то сделать»
🟣Если что-то хорошо работает, оно не должно хорошо работать. Просто вы еще не знаете, что именно работает плохо

Про карьеру

🟡«Синьор одного проекта» - не имеет достаточного опыта с процессами, с другими командами, с решением кейсов
🟡Фидбек интервьюера на собесе: «Иногда важно не что отвечает, а как»

Про менеджерство

🔴Микроменеджмент - недостаток доверия - ревность
На одной конфе сказали левую половину фразы. Я подумала, что ревность тоже возникает от недостатка доверия. Значит ли это, что микроменеджмент = ревность? 🤔
🔴Я не понимаю, почему в играх ты повышаешь уровень, когда все проходишь без ошибок. Ведь ты получаешь новые уровни, когда ошибаешься. Ошибка - ресурс, который конвертируется в результат
🔴Проджект менеджер - это пастух встреч

Про технику

⭕️База данных - всего лишь кэшированная версия журнала (т.к. в ней последние значения полей, а в журнале - все)
⭕️В потоках сортировка слиянием неприменима, т к. сортировка невозможна на бесконечном наборе данных
⭕️CDC - это хак, журналы низкоуровневые и до определенного момента не использовались
⭕️В Hadoop используется концепция «складывай как есть, потом решим». Однако на практике выясняется: быстро получить данные, даже представленные в странном, трудном для применения, необработанном формате, зачастую более ценно, чем пытаться заранее выбрать идеальную модель данных
⭕️Для разных людей по-разному могут работать сайты - для активных пользователей быстрее, для пассивных - дольше (не факт, что это реальная инфа, но мысль интересная)

Про безопасность

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

Про красивое

🟣Учусь дышать над поломанным смыслом
🟣Инерция пылинки

Про байки

На одной из конф рассказывали байки, одна из них меня очень зацепила:

🔴Правда или ложь: если человеку, который купил вещь, в течение недели/месяца не показывать похожие вещи в рекомендациях, то конверсия в продажи вырастет?

❤️ - правда
🤔 - ложь
Please open Telegram to view this post
VIEW IN TELEGRAM
32🤔8
Возможен ли Sort-Merge Join без шафла?

Ага, в спарке есть такая оптимизация - Storage Partition Join (SPJ). Если таблицы одинаково партиционированы и джойнятся по этому ключу, то не приходится перемещать кучу данных. Правда, это работает только в форматах, поддерживающих DataSource API V2. Например, в Iceberg, Hudi, Delta Lake

Что нужно:

🌸 Spark 3.3+
🌸 Условие равенства в джойне
🌸 У таблиц должно быть общее поле-партиция, которое входит в ключ джойна

🎈 Пример

Я взяла 2 таблицы, партицировала, заполнила данными и положила. Потом их поджойнила, и вот какой план запроса у меня сначала получился (картинка 1):


== Physical Plan ==
CollectLimit
+- * Project
+- * SortMergeJoin Inner
:- * Sort
: +- Exchange
: +- * Project
: +- BatchScan spark_catalog.test.table1
+- * Sort
+- Exchange
+- * Project
+- BatchScan spark_catalog.test.table2


У нас есть Exchange - происходит шафл даных. Потом я накинула несколько конфигов:


# включает Storage Partition Join
spark.conf.set("spark.sql.sources.v2.bucketing.enabled", "true")

# сохраняет текущее партиционирование при планировании запроса
spark.conf.set("spark.sql.iceberg.planning.preserve-data-grouping", "true")

# убирает шафл, когда партиции между таблицами не совпадают по количеству
spark.conf.set("spark.sql.sources.v2.bucketing.pushPartValues.enabled", "true")

# иначе ключи джойна должны быть такие же, как партиции, в том же порядке
spark.conf.set("spark.sql.requireAllClusterKeysForCoPartition", "false")

# борется с перекосом данных
spark.conf.set("spark.sql.sources.v2.bucketing.partiallyClusteredDistribution.enabled", "true")

# разрешает включать части партиций в ключ джойна
spark.conf.set("spark.sql.sources.v2.bucketing.allowJoinKeysSubsetOfPartitionKeys.enabled", "true")

# на всякий можно отключить broadcast, адаптивку и sortmerge (если это точно нужно)
spark.conf.set("spark.sql.autoBroadcastJoinThreshold", -1)
spark.conf.set("spark.sql.adaptive.enabled", "false")
spark.conf.set("spark.sql.join.preferSortMergeJoin", "false")


План запроса чуть поменялся (картинка 2) - исчез шафл:


== Physical Plan ==
CollectLimit
+- * Project
+- * SortMergeJoin Inner
:- * Sort
: +- * Project
: +- BatchScan spark_catalog.test.table1
+- * Sort
+- * Project
+- BatchScan spark_catalog.test.table2


В одной из статей говорится, что перформанс увеличился на 45-70% на джойнах. А кто-то уже использовал на практике?

@data_engineerette
Please open Telegram to view this post
VIEW IN TELEGRAM
137🤔1
Минутка рефлексии

Не люблю рефлексировать, потому что это всегда вгоняет меня в тоску😔 Но мем прям метчится со мной. У меня практически никогда не бывает такого, что я прыгаю от радости или злюсь и агрессирую. Мне просто норм

Вот вы пишете код, sql-запросы, копаетесь в логах ошибок, запускается пайплайны, уточняете требования, ресерчите источники данных, делаете преобразования, нажимаете на кнопочки, стучите по клавиатуре - это вам в кайф? Думаете ли вы: "Уррра, завтра я буду разбираться в проблемах с качеством данных"? "Наконец-то этот поток упал, чтобы я выяснил все проблемы и поднял его"?

Вот в конце июля опубликовали 2025 Stack Overflow Developer Survey, и там всего лишь 25% людей прям счастливы на работе. Остальным 25% вообще не нравится, 50% ок
Please open Telegram to view this post
VIEW IN TELEGRAM
16😭11👍6
Как ускорить ClickHouse?

Обсуждали с одним де перформанс систем и связку Trino + ClickHouse. Моя первая мысль - серьезно? КХ и так быстрый, куда еще к нему Trino накручивать?? Моя вторая мысль - тестим! Дисклеймер - мои тесты не претендуют на супер истину, но дают определенное представление

💻 Я взяла ноут, подняла кх с 1 нодой и трино с кх каталогом. Создала тестовые таблички с 1к, 10к, 100к, 1млн, 10млн строк. Больше уже не отрабатывало

Придумала такой запрос:


with cte as (
select
id,
concat(cast(id, 'String'), '_', cast(id, 'String')),
sum(id),
row_number() over (order by id) as rn
from test.tbl1000
group by 1, 2
)
select * from cte
where rn in (14, 49)
order by rn desc


Тут есть работа со строками, агрегация, оконка и т.д. - поэтому тестим в какой-то мере тяжелую операцию

Запрос я запустила по 50 раз на каждом размере данных для кх и трино. Потом так же погоняла insert моей cte в таблицу

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

По итогу решила сравнить время: query_duration_ms vs elapsedTime

Какие выводы я могу сделать:

1. Трино поверх КХ проигрывает КХ. Так получилось при моих данных и в моих условиях. Хотя есть мнение, что на большом объеме данных он работает быстрее бд (~100гб)

2. При insert трино проигрывает еще значительнее, потому что сначала пишет данные во временную таблицу, потом перекладывает в основную:


INSERT INTO "test"."result1000" ("id", "str", "sum_", "rn") SELECT "id", "str", "sum_", "rn" FROM "test"."tmp_trino_c5cb30af" temp_table


3. В query_log по Трино не собирается часть метрик: user_aggregate_functions, used_functions, used_data_type_families. А также отличаются result_rows, query. Если это важно для мониторинга, то использовать не получится

4. Я также хотела отделить разные тесты комментами, чтобы потом удобнее искать в query_log:


SETTINGS log_comment = 'test'


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

@data_engineerette
Please open Telegram to view this post
VIEW IN TELEGRAM
👍24🌚1
Понедельничная мантра

Всем прекрасной рабочей недели🐾
Please open Telegram to view this post
VIEW IN TELEGRAM
😁33🔥144😭2💅1
Как движки вас газлайтят?

Расскажу историю, которая на днях прозошла на нашем кластере

💋Что надо сделать? Создать табличку и запустить пайплайн заливки данных. Казалось бы - что может быть проще?

1. Создаем таблицу в Trino:


CREATE TABLE iceberg.raw.first_table (
my_beautiful_column varchar
)
WITH (
format = 'PARQUET',
format_version = 2
)


2. Запускаем пайплайн - создается веточка:


ALTER TABLE raw.first_table
CREATE OR REPLACE BRANCH my_branch



SELECT *
FROM iceberg.raw."first_table$refs"
--main BRANCH
--my_branch BRANCH


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

Но в один момент я создаю таблицу через Spark:


CREATE TABLE raw.second_table (
my_beautiful_column STRING
)
USING iceberg


Снова запускаю пайплайн, и он снова падает. Я правлю ошибку и перезапускаю...


Exception in thread "main" java.lang.IllegalArgumentException: Cannot complete replace branch operation on raw.second_table, main has no snapshot


Что случилось? Таблица точно такая же, код точно такой же. Просчитался, но... где? 🤔

😑 Тут начинаются раскопки. Создаю табличку через трино и через спарк, иду на s3 смотреть файл с метаданными

Оказывается, что трино создает отдельный снепшот с добавлением 0 строк:
🤍"current-snapshot-id" : 677178324561195060
🤍таблица raw.first_table.history имеет 1 строку

А спарк такого не делает - он их создает, только когда данные меняются, компактятся:
🤍"current-snapshot-id" : -1
🤍таблица raw.second_table.history пустая

Теперь идем в репку айсберга, а там такое:


if (create && replace && !refExists) {
safeCreateBranch()
} else if (replace) {
Preconditions.checkArgument(snapshotId != null,
"Cannot complete replace branch operation on %s, main has no snapshot", ident)
manageSnapshots.replaceBranch(branch, snapshotId)
}


🩵Какой ход событий получается:

1. Попадаем в условие if: create есть, replace есть, ветки еще нет. Ветка создается
2. Пытаемся записать данные в ветку
3. Код падает, а ветка остается(!)
4. Перезапускаем и в условие if уже не попадаем - ветка уже есть
5. Попадаем в else if (replace) - вспоминаем, что через спарк никакой снепшот не создается, поэтому snapshotId у нас null

➡️ Как решаем проблему

Перед созданием ветки нужно дропнуть существующую, если вдруг пайплайн упал и не успел почистить ветку:


ALTER TABLE raw.second_table
DROP BRANCH IF EXISTS my_branch


Либо добавить catch/except, который дропнет ее в самом конце

Общий вывод такой: при работе с разными движками любой кусок может работать по-разному. Даже самая простейшая штука, которую вы не ожидали🥺

@data_engineerette
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18🔥961💯1
SQL Advent. Day 1

Сегодня стартовал адвент по sql! К сожалению, орг прошлогоднего адвента решил в этом году его не делать 😪
Но я нашла еще один!

🤩всего 24 дня
🤩задания открываются в 17:00 по мск

Первый день супер легкий, погнали вместе проходить)

📍 Полезные ссылки

Адвент календарь (с впн)

Мои решения
Please open Telegram to view this post
VIEW IN TELEGRAM
257
SQL Advent. Day 2

Сегодня задание на джойн)

Заметила, что ллмка анализирует твое решение и пишет в чат моменты на улучшение:

To make sure you only get unique toy IDs and names (in case a toy was delivered multiple times), you might want to consider using DISTINCT. Also, ordering the results can make the output easier to read.


📍 Полезные ссылки

Адвент календарь

Мои решения
Please open Telegram to view this post
VIEW IN TELEGRAM
8
SQL Advent. Day 3

Уровень hard - уже похоже на задачки с собесов. На скрине одна из таких - когда нужно найти топ по каждой категории

📍 Полезные ссылки

Адвент календарь

Мои решения
Please open Telegram to view this post
VIEW IN TELEGRAM
7
Тимлидский митап

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

1️⃣ "Поедатели времени команды"

Этот доклад я слушала особенно внимательно, он в меня попал на 100%. Я выделила по несколько моментов, которые особенно меня зацепили

➡️ затянутые стендапы

➡️ постоянное переключение контекста

Это и про мгновенный ответ на сообщения, включенные уведомления. У меня есть такая проблема, я хочу быть в курсе, даже если меня не особо касается😒 Но я хотя бы научилась игнорить красные плашки. Поэтому сейчас я живу между "прочитано сразу" и "прочитано почти никогда"

Сюда еще относится слишком много экспертизы в одних руках - это забавно)) А также несколько встреч с перерывом в 30мин/1ч. В таких случаях я чувствую, что надо и водички попить, и на сообщение ответить, и задачку доделать, и вопросы к новой встрече просмотреть, и подготовить свою часть - и вот уже надо снова брать наушники и подключаться. А время-то куда делось?

Из особо полезного:
- договориться о фокус-времени - вся команда работает с 11 до 14 и друг друга не отвлекает
- просматривать входящие по расписанию - раз в 1-2ч, а не сразу

➡️ проблема неделегируемых задач

- bus factor - что будет, если дать задачу другому?
- составить список уникальных умений и людей, выбрать наследника 👑

➡️ долгие обсуждения и затянутые ревью

- если много вопросов, делить на несколько встреч
- ограничить размер PR
- нечетное количество ревьюеров - чтобы одно из полярных мнений подкрепил кто-то еще
- SLA на время реакции на ревью

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

2️⃣ "Как удобрять инженера, чтобы вырос крепкий лид"

Тут 2 проблемные ситуации:
🤩Есть желающие -> нет ставки
🤩Нужен лид -> нет желающих

Сначала нужно договориться, кого отдаем, какие задачи делегируем (1:1, решение проблем команды, отслеживание метрик, отчеты по работе). После определенного срока собираем ОС. В итоге сняли немного инженерных задач, накинули менеджерских

Растить лида внутри или брать снаружи?
🤩Сложные задачи, кризис-менеджмент - опытный с рынка/из соседних подразделений
🤩Есть время на сопровождение, обучение - свой

Также спикер упомянула про ресурсы для взвращивания лида. Я попросила ссылочку

3️⃣ "Собираем Dream Team"

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

4️⃣ "Сообщество как ресурс руководителя"

Как сообщества ускоряют онбординг, повышают компетенции, облегчают работу лида, унифицируют стек и процессы

Youtube
VK

@data_engineerette
Please open Telegram to view this post
VIEW IN TELEGRAM
112🔥4
Data Value Design Patterns

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

🎨 Data Enrichment

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

Pattern: Static Joiner - обычный джойн двух таблиц
Pattern: Dynamic Joiner - джойн двух потоков с временным окном

🤩 Data Decoration

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

1️⃣Pattern: Wrapper

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

Мы такой подход используем. Но если требования часто меняются, то я бы все доп поля вынесла в один struct/json

2️⃣Pattern: Metadata Decorator

Мы хотим делать все то же самое, но не показывать пользователям технические поля. Тогда:

🤩Для бд создать вьюшку без тех полей или запретить чтение определенных столбцов на уровне прав
🤩Для s3 есть штука с тегами, их можно навесить на весь файл. Теги - это пара ключ-значение: mytag=myvalue. Как работать с тегами можно полистать тут
🤩Для отправки в кафку писать в header

🌸 Data Aggregation

Как под капотом происходит агрегация данных

1️⃣Pattern: Distributed Aggregator

Это про шаффлы в распределенных системах. В контексте шафла важно учитывать data skew. С ним можно бороться, например, такими способами:

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


dataset.withColumn("salt", (rand() * 3).cast("int"))
.groupBy("group_key", "salt").agg(...)
.groupBy("group_key").agg(...)


🤩включить AQE - адаптивку в спарке. Ниже полезные конфиги, с которыми мы работаем:


spark.sql.adaptive.enabled - включает адаптивку

spark.sql.adaptive.advisoryPartitionSizeInBytes - объединяет мелкие партиции или разделяет крупные

spark.sql.adaptive.skewJoin.enabled - разделяет партиции в джойнах

spark.sql.adaptive.skewJoin.skewedPartitionFactor - кэф для определения крупной партиции

spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes - то же самое, только в байтах


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

External Shuffle Service в Spark как раз хранит данные шафла отдельно. Когда посчиталось, ресурсы ноды могут отправиться другому приложению, потому что данные шафла в безопасности

2️⃣Pattern: Local Aggregator

В контексте спарка мне показалось, что это про broadcast

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

#depatterns
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥64👍4
SQL Advent. Days 4-7

Решила объединить, потому что в уровне easy (4 и 7 день) нужно написать всего по 3-4 строчки

День 5 потребовал от меня несколько попыток, потому что условие было неполным. Пыталась ориентироваться на подсказки, но они как будто уводили меня еще дальше))

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


coalesce(max(return_date), 'Still resting')


День 6 потребовал разложить горнолыжки по 4 бакетам в зависимости от уровня снега. По-моему, впервые применила функцию ntile:


ntile(4) over (order by total_snowfall_inches)


📍 Полезные ссылки

Адвент календарь

Мои решения
Please open Telegram to view this post
VIEW IN TELEGRAM
👍104🔥4
Мысли с матемаркетинга

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

🤩"Эволюция аналитических платформ в XXI веке"

"Если ваша команда дата инженеров ковыряет лейкхаус, то ваш стек отстал года на 4. А если нет - то, возможно, и на все 10"

"Строить лейкхаус-платформу - это все равно, что построить заново СУБД"

В своих заметках еще нашла такую подходящую:

"Когда новая технология накатывает на вас как асфальтоукладчик и вы не у него за рулем, вы становитесь частью дороги"

Еще спикер упомянул про агентскую платформу от Databricks и The Data Engineering Agent от Google

Меня немножко задемотивировало, а вы что думаете? Мы тут все отстающие или стабильные? 😁

🤩"Как найти и как себя вести с сотрудниками, которые не перформят"

Социальная лень - когда один человек понимает, что ответственность размазана по коллективу, и снижает планку => все снижают планку

Токсик продуктивити - много шума, реального результата мало

Когда человек не перформит, есть несколько вопросов к себе на подумать:

🤩Если бы человек ушел - вы бы обрадовались или расстроились?
🤩Сколько денег дают на новую вакансию?
🤩Ок, если 3-4 месяца будем искать?
🤩А если уже на деньги мидла можно найти только джуна?
🤩Что думают доверенные сеньоры про онбординг нового человека?

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

А когда мы отбирали кандидатов на собес или решали по офферу, то руководствовались принципом: сомнение = нет

🤩"Сложные кейсы: как тимлиду грамотно расстаться с неэффективным сотрудником"

Если вы руководитель, то будьте готовы, что вас постоянно записывают. Сюда относятся записи из онлайн встреч, экспорт чата, личные чаты, диктофонные записи. Получается, работа лида - это как разведка, ничего лишнего болтать не надо 🤭

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

🤩"Новый потребитель: как появился сегмент, которого не должно было быть"

Тут рассказывали про покупателей с "неадекватным" поведением в 2022-2024 в отдельных регионах. Они внезапно получили много денег, которых у них никогда не было, и начали покупать то, что никогда не покупали

Еще рассказывали про другой подход к ритейлу - если раньше в магазинах брали много, то сейчас люди делают несколько заказов по 100 рублей (я сама так делаю, хотя чувствую, что неразумно)

🤩"Виртуальная очередь в Яндекс Go: как мы сделали поиск такси предсказуемым в пике"

Этот доклад про оптимизацию, когда много людей уезжает одновременно со стадиона/из театра

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

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

Лайк за доклад, очень все понятно и применимо 👍 А так большинство докладов уже совсем не метчится с моими интересами🥲
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔6🔥5👍21
Стартанул новый Advent of SQL!!!

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

Мне оочень понравился формат - они записывают видосы с заданием! И какой же харизматичный спикер, какой у него красивый акцент 🥰🥰

К видосу прилагается файл с данными. Данных прям много, около 500к строк для одной таблицы. Я как раз на днях перешла на DataGrip и теперь полноценно работаю с ним. Там можно просто тыкнуть SQL Scripts -> Run SQL Script... и выбрать скачанный файлик

У них также есть своя песочница, поднимается за 30 сек со всеми данными

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

🤩всего 15 дней
🤩задания открываются в 21:00 по мск

📍 Advent of SQL (с впн)
📍 SQL Advent Calendar (с впн)
📍 Мои решения
Please open Telegram to view this post
VIEW IN TELEGRAM
9👍7
Advent of SQL. Days 2-3

📺 Видосы с каждым днем становятся длиннее, вчера было уже почти 12 минут! Задача была на использование ilike - это регистронезависимый like, in, case when. Не думала, что update/delete можно применять, но в этих задачках можно... Главный совет - обязательно перепроверить себя селектом перед изменением данных

🏴󠁧󠁢󠁥󠁮󠁧󠁿 Решила вести словарик с новыми фразами. Так что фразы дня:

🤩rowdy children - шумные дети
🤩interstitial break - промежуточный перерыв
🤩repentant kids - раскаивающиеся дети
🤩yoink - восклицание, когда человек что-то быстро берет

И мне особенно понравились такие комментарии автора:


Я мог бы написать where tag = '' or tag = '', но я не пещерный человек

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



Про конструкцию count(*) FILTER (WHERE ...) в Postgres:


Вы можете услышать, что люди вам не рекомендуют использовать этот вариант, потому если вдруг сменится база данных... Но если вы когда-нибудь поменяете продовую бд, у вас будет много проблем. и CASE vs FILTER - это самая простейшая из них



📍 Advent of SQL (с впн)
📍 SQL Advent Calendar (с впн)
📍 Мои решения

@data_engineerette
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Advent of SQL. Day 4

Задачка на приведение данных к единому формату и применение like, ilike, case when, union

В одном из case мне нужно было сделать assigned_task ilike '%snow%' or assigned_task ilike '%shovel%', но это так скучно)) Поэтому я пошла гуглить другие варианты, нашла такие:


where assigned_task ~* 'snow|shovel'

where lower(assigned_task) similar to '%(snow|shovel)%'

where assigned_task ilike any (array['%snow%', '%shovel%'])

where assigned_task ilike any('{%snow%,%shovel%}')


Раньше я пользовалась только ~~ вместо like. Но оказалось, для остальных тоже есть свои символы. not ilike - это вообще что за демон?


like ~~
ilike ~~*
not like !~~
not ilike !~~*


А также я узнала нагуглила функцию initcap. В одной из таблиц данные уже были в едином формате, их нужно было привести к другому: stage_setup -> Stage Setup. initcap как раз делает то, что нужно: она каждое слово в строке пишет с заглавной буквы:


select initcap(replace(role, '_', ' ')) as role


🏴󠁧󠁢󠁥󠁮󠁧󠁿 Фразы дня

wonky list/space - кривой список/пробел
volunteer roster - список/расписание волонтеров
handwarmer handout - раздача грелок для рук
studly case = pascal case = StudlyCaps - название в формате MyClassName
strong suit - сильная сторона

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

📍 Advent of SQL (с впн)
📍 SQL Advent Calendar (с впн)
📍 Мои решения

@data_engineerette
Please open Telegram to view this post
VIEW IN TELEGRAM
👍73
Advent of SQL. Days 5-6

На пятой задаче было топ-3 через row_number и cte - мы с подобной штукой уже встречались ранее:


row_number() over(partition by user_name order by count(1) desc) as rn


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

Перечитала summary дважды и посмотрела дважды видос. Решила послушать подсказку - спикер посоветовал использовать "эзотерический" джойн. И почему моя первая мысль была про asof join, я даже пошла гуглить примеры 😁

Потом решила, что не может быть такого задания, когда в предыдущем мы всего лишь применяли оконку🥺 В итоге формула решения такая: generate_series + cross join + left join

📍 Advent of SQL (с впн)
📍 SQL Advent Calendar (с впн)
📍 Мои решения
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
Advent of SQL. Days 7-8

☕️ На 7й день мы распределяли посетителей по разным какао-станциям на основе их вкусовых предпочтений. Для этого нужно было вспомнить про пересечения и агрегацию массивов

Получилось такое условие джойна, оно возвращает true, если массивы пересекаются:


left join available_cocoa_cars c
on p.favorite_mixins && c.available_mixins


А так можно красиво собрать все доступные какао-станции по каждому посетителю. Про сортировку даже не вспомнила, что ее можно туда засунуть:


select
passenger_name,
array_agg(c.car_id order by c.car_id)
from ...
group by passenger_name


🌄 На 8й день произошло целое открытие для меня. Все это время существовала концепция named window, а я ни разу ее не видела??😱

Мы определяем окно в самом конце запроса типо как cte и можем переиспользовать название окна в расчетах столбцов:


select
product_id,
price as product_price,
lead(price) over w as previous_price,
row_number() over w as rn
from price_changes
window w as (
partition by product_id order by effective_timestamp desc
)


Причем этот синтаксис работает просто везде: PostgreSQL, MySQL, ClickHouse, Spark SQL, Oracle, Vertica... Что? 😍 Почему это так удобно, но нигде не используется?

📍 Advent of SQL (с впн)
📍 SQL Advent Calendar (с впн)
📍 Мои решения
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍21
Хотите побыть Дедом Морозом?

Новый год - это пора чудес И сегодня вы можете помочь исполнению новогоднего чуда!

У нас в ламоде проводится конкурс мерча. И если вы хотите, чтобы его получила я - то буду благодарна за вашу подписку 🙂🙂

А вообще в канале рассказывается много чего интересного:

🤩статьи на хабре
🤩записи с выступлений
🤩внутренние новости
🤩карточки с полезностями
🤩мемасики
🤩а также проводятся новогодние розыгрыши - сейчас есть активный до 22го декабря🎄
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍3🔥2🤔2😁1