BA & SA | 10000 Interview questions
10.2K subscribers
172 photos
14 videos
342 links
Вопросы и задачи, которые задают на собеседованиях на позицию Бизнес и Системного аналитика. По вопросам сотрудничества- @DeliveryManager7
Download Telegram
ИИ — ЭТО УЖЕ НЕ «КОГДА-НИБУДЬ ПОТОМ» ... ОН ПРЯМО СЕЙЧАС ПЕРЕПИСЫВАЕТ ПРАВИЛА ИГРЫ 🖋

Тексты, аналитика, продажи, дизайн, экономия десятков часов в неделю — это не футурология.
Это ваш обычный вторник, если вы в теме.

Вопрос больше не в том, заменит ли ИИ людей.
Вопрос в том, кто обгонит вас, пока вы раздумываете.


Хотите быть среди первых, кто использует нейросети на все сто?

Тогда вот что вам нужно ⚡️:
👉 ПОДБОРКА реально сильных и продвинутых экспертов по нейросетям, ИИ, IT & HR Tech, а также последние - AI Life hacks

Забирайте, пока другие бездумно скролят ленту новостей.
Отписаться можно в любой момент — без проблем ✔️

Ссылка на ПАПКУ ⬇️
https://t.me/addlist/3PXSBSiaHSc2ZWRk * Добавляйте себе в избранное и скидывайте ссылку коллегам.
👍1🔥1
№4780 категория вопросов: #TESTING
4780. При бронировании билетов система не блокирует места на время оплаты — другой пользователь может их перехватить. Разработчики ссылаются на требования. Кто упустил сценарий?
Anonymous Quiz
1%
Разработчики
9%
Тестировщики
87%
Аналитик
3%
Архитектор
Объяснение:

Суть проблемы
Требование могло звучать как: «Пользователь может забронировать место». Ни слова про то, что место должно блокироваться на время оплаты, чтобы его не перехватил другой. Разработчик реализовал только бронирование без блокировки, и это формально соответствует букве требования. Но бизнес ожидал стандартного для таких систем поведения (блокировка на 10–15 минут). Проблема — в неполноте требований, а именно — в отсутствии сценария конкурентного доступа.

Почему это зона ответственности аналитика?

Аналитик должен выявлять и описывать нефункциональные и логические требования, которые кажутся «очевидными» бизнесу, но не очевидны разработчику.
Конкурентный доступ (race condition) — классический сценарий для систем бронирования. Аналитик обязан был задать вопрос: «А что, если два пользователя попытаются забронировать одно место?».
Критерии приемки (Acceptance Criteria) должны включать примеры с одновременными действиями.

Почему не другие варианты:

A (разработчики) — они реализовали требования «как есть». Без явного указания на блокировку у них нет оснований её делать.
B (тестировщики) — тестировщики проверяют соответствие требованиям. Если в требованиях нет сценария с параллельным бронированием, они могут его не проверить.
D (архитектор) — архитектор может предложить техническое решение (пессимистические блокировки), но только если есть соответствующее требование.
Как должно было быть в требованиях:
Аналитик должен добавить в критерии приемки:

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

Пользователь А выбирает место и начинает бронирование.
Пользователь Б пытается выбрать то же место.
Ожидаемый результат: Б видит сообщение «Место временно заблокировано другим пользователем».

Реальный кейс
В одной авиакомпании при запуске нового сайта пассажиры жаловались, что после выбора места и ввода данных карты место вдруг становится недоступным — его успевал перехватить другой пассажир, более быстрый на оплату. Компания потеряла сотни тысяч рублей на возвратах и компенсациях. Аналитик не прописал блокировки, хотя в предыдущей системе они были. После инцидента требования дополнили, и блокировки внедрили.

Вывод: Аналитик обязан выявлять неочевидные сценарии, такие как конкурентный доступ, и явно описывать их в требованиях. «Очевидные» вещи для бизнеса не очевидны для разработчиков. Пропуск такого сценария — прямая ответственность аналитика, а не разработки или тестирования. 🎯

#TESTING
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
Если вы хотите зарабатывать в Telegram, вам нужна эта папка.

Там собраны материалы по:

— продвижению каналов
— маркетингу
— инфобизнесу
— привлечению трафика
— монетизации

Это концентрат знаний, который обычно собирают годами.

Очень часто мне пишут:

«Почему канал не растёт?»
«Где брать подписчиков?»
«Как начать зарабатывать в Telegram?»

И почти всегда проблема одна — нет системного понимания продвижения и маркетинга.

По сути, это концентрат знаний, который обычно собирается по крупицам из разных источников.

Я просто сделала удобную подборку, чтобы всё было в одном месте.

Если вы:
— ведёте канал
— развиваете личный бренд
— продаёте услуги
— или только хотите начать зарабатывать в Telegram

сохраните папку и добавьте её себе.

Переходите по ссылке
https://t.me/addlist/PE0khuyk7UY0YjFi

Записывайся в подборку🫶
Please open Telegram to view this post
VIEW IN TELEGRAM
№4781 категория вопросов: #DBMS
4781. В таблице orders 100 млн записей. Запрос на сумму заказов за последний месяц выполняется 30 секунд. Индекс на order_date есть. Что ещё можно сделать для ускорения без изменения кода?
Anonymous Quiz
6%
Заменить индекс на хеш-индекс
52%
Создать материализованное представление с предрасчётом агрегатов
36%
Добавить партиционирование по order_id
5%
Увеличить кэш базы данных
Объяснение:

Проблема:
Запрос SELECT SUM(amount) FROM orders WHERE order_date >= ... даже с индексом на order_date должен прочитать все строки за последний месяц. Если за месяц 10 млн записей, база данных выполняет полное сканирование этих 10 млн строк (пусть даже по индексу). 30 секунд — это много для отчёта, который нужен часто.

Почему индекс не спасает?
Индекс помогает быстро найти строки по условию WHERE, но агрегация (SUM) всё равно требует чтения всех отфильтрованных строк из таблицы (или из индекса, если индекс покрывающий). Если объём данных за месяц велик, время будет большим.

Правильное решение — материализованное представление (B):

Материализованное представление — это физическая таблица, которая хранит предварительно вычисленные агрегаты.

Можно создать:

```sql
CREATE MATERIALIZED VIEW monthly_sales AS
SELECT DATE_TRUNC('month', order_date) AS month, SUM(amount) AS total
FROM orders
GROUP BY month;
```
Запрос к этому представлению читает всего несколько строк (по количеству месяцев), а не миллионы. Время выполнения падает до миллисекунд.

Недостаток: данные нужно обновлять (полностью или инкрементально), но для отчёта с допустимой задержностью (например, обновлять раз в час) это отличное решение.

Почему не подходят другие варианты:

A (хеш-индекс) — полезен только для поиска по точному равенству, не для диапазонов и агрегаций.

C (партиционирование по order_id) — не имеет смысла для запроса по дате; партиционирование должно быть по дате, но даже с ним агрегация всё равно читает все партиции за месяц. Ускорение будет незначительным.

D (увеличить кэш) — кэш может помочь, если запрос выполняется часто и данные уже в памяти, но при первом выполнении или при большой выборке кэш не спасёт.

Реальный кейс:
В крупном онлайн-кинотеатре отчёт «выручка по месяцам» на таблице с миллиардами просмотров выполнялся 2 минуты. Создали материализованное представление, обновляющееся раз в сутки. Время отклика упало до 0.05 секунды. Маркетологи стали работать в 10 раз быстрее.

Что должен зафиксировать аналитик:

Определить, какие агрегатные отчёты критичны по времени.

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

Согласовать допустимую задержку обновления (real-time / near real-time / ежедневно).

В требованиях указать необходимость создания и обслуживания таких объектов.

Вывод: Материализованные представления — это стандартный способ ускорить тяжёлые агрегатные запросы на больших таблицах, когда допустима небольшая задержка актуальности данных. Аналитик, знающий этот механизм, может спасти производительность без сложных архитектурных изменений. 🎯

#DBMS
Please open Telegram to view this post
VIEW IN TELEGRAM
№4782 категория вопросов: #DBMS
4782. Запрос SELECT * FROM orders WHERE status = 'NEW' выполняется 10 секунд, хотя в таблице всего 10 млн строк и статус «NEW» имеют 50% записей. Индекс на status есть, но запрос всё равно медленный. В чём причина?
Anonymous Quiz
3%
Индекс повреждён, нужно перестроить
81%
Оптимизатор выбрал полное сканирование таблицы, так как селективность низкая (50%)
15%
Нужно добавить хеш-индекс
1%
Проблема в кэше базы данных
Объяснение:

Суть проблемы
Индекс ускоряет поиск, если условие отбирает малую долю строк (высокая селективность). Если условие отбирает половину таблицы (50%), оптимизатор может решить, что дешевле прочитать всю таблицу последовательно, чем делать много случайных чтений по индексу. В этом случае он игнорирует индекс и выполняет full table scan.

Почему индекс не используется при низкой селективности?

Индекс сначала находит ID строк, потом идёт к таблице за данными (через heap). Это случайные чтения.
При 50% выборке случайные чтения могут быть дороже последовательного сканирования всего 10 млн строк.
Оптимизатор оценивает стоимость (cost) и выбирает план с наименьшей стоимостью.
Как проверить?
Команда EXPLAIN (ANALYZE) покажет план выполнения:

Seq Scan — полное сканирование таблицы.
Index Scan — чтение по индексу.
Если видите Seq Scan при наличии индекса — скорее всего, виновата низкая селективность.
Что делать, если действительно нужно выбрать 50% строк?

Индекс бесполезен. Нужны другие методы:

Секционирование (партиционирование) по status, чтобы читать только нужную партицию.
Покрывающий индекс, включающий все поля SELECT, чтобы не ходить в таблицу (Index Only Scan).
Материализованное представление, если данные обновляются нечасто.

Почему не другие варианты:

A (индекс повреждён) — при повреждении были бы ошибки, а не просто медленное выполнение.
C (хеш-индекс) — не подходит для неравенств и диапазонов, к тому же в PostgreSQL он не поддерживает восстановление после сбоев.
D (кэш) — не поможет при первом выполнении и при большом объёме данных.
Реальный кейс
В CRM-системе был запрос на всех активных клиентов (статус = ACTIVE, 45% от 50 млн). Запрос выполнялся 20 секунд, хотя индекс был. DBA объяснил, что индекс для такого объёма неэффективен. Решение: добавили партиционирование по статусу и изменили логику — теперь читают отдельную партицию ACTIVE за миллисекунды.

Что должен сделать аналитик:

Анализировать селективность будущих условий. Если условие отбирает >10–20% строк, индекс может не помочь.
Требовать EXPLAIN-тестирование на данных, близких к боевым.
Для часто используемых фильтров с низкой селективностью предлагать партиционирование или материализованные представления.
Не назначать индексы вслепую — понимать, когда они полезны, а когда бесполезны.

Вывод: Индекс — не панацея. Он эффективен только для высокоселективных условий (<5–10%). Аналитик, понимающий этот принцип, сэкономит ресурсы БД и время разработки. 🎯

#DBMS
Please open Telegram to view this post
VIEW IN TELEGRAM
1
№4783 категория вопросов: #DBMS
4783. В sharding-БД новые записи с автоинкрементным BIGINT всегда попадают в один шард, создавая «горячую точку». Какой тип первичного ключа нужно было выбрать на этапе проектирования?
Anonymous Quiz
8%
SERIAL с другим начальным значением
31%
UUID v4 (случайный)
58%
Составной ключ (shard_id, local_id)
3%
UUID v1 (временной)
IT-специалисты и диджитал-эксперты! 📈 Недавно прочитали интересную статистику: 73% компаний замедлили цифровую трансформацию из-за нехватки экспертизы и подходящих инструментов — это хороший повод задуматься о своих процессах.

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

Поэтому рекомендуе вам эту подборку для диджитал и IT — чек-листы по трансформации, скрипты автоматизации, кейсы импортозамещения и материалы по ИИ-оптимизации.

Сохранить подборку себе 📨
Объяснение:

Проблема:
При шардировании (горизонтальном масштабировании) данные распределяются по узлам на основе значения первичного ключа. Автоинкрементный BIGINT порождает последовательные, монотонно растущие числа (1, 2, 3…). При шардировании по хешу или диапазону все новые значения попадают в один и тот же шард (последний по диапазону или определённый бакет хеша). Этот шард перегревается, а остальные простаивают. Возникает «горячая точка», которая убивает масштабируемость.

Почему UUID v4 — решение:

· UUID v4 генерирует случайные 128-битные значения.
· При шардировании по хешу случайные значения равномерно распределяются по всем шардам.
· Нагрузка распределяется равномерно, горячих точек нет.
· Это стандартный паттерн для крупных распределённых систем (например, Cassandra рекомендует UUID).

Почему не подходят другие варианты:

· A (другой старт) — проблема не в старте, а в монотонности; даже если начать с 1 000 000, последовательность всё равно будет попадать в один шард.
· C (составной ключ) — технически возможен, но требует дополнительного слоя координации для генерации shard_id, что сложнее и тоже может создать горячую точку.
· D (UUID v1) — генерируется на основе временной метки и MAC-адреса, то есть монотонен по времени, что частично повторяет проблему автоинкремента (новые UUID будут близки по значению и могут попадать в один шард при диапазонном шардировании).

Компромисс и нюансы:

· В InnoDB (MySQL) кластерный индекс по случайному UUID может вызывать фрагментацию индекса и замедлять вставку (каждая новая запись вставляется в случайную позицию).
· Альтернативы: UUID v7 (временная составляющая + случайность) или Snowflake-подобные ID (время + порядковый номер + ID узла). Они дают приблизительную монотонность, но при шардировании по хешу всё равно распределяются равномерно.
· Если база данных позволяет использовать UUID в качестве первичного ключа с некластерным индексом, проблема фрагментации снижается.

Реальный кейс:
В одной финтех-компании использовали автоинкремент для транзакций. При росте до 1000 транзакций/сек один из 64 шардов обрабатывал 95% записей, остальные простаивали. Перешли на случайный UUID — нагрузка выровнялась, и система смогла масштабироваться до 50 000 транзакций/сек без изменений железа.

Что должен зафиксировать аналитик:

· При планировании шардирования указать, что первичный ключ должен быть случайным (UUID v4) или распределённо-уникальным с хорошей равномерностью (Snowflake).
· Учитывать особенности СУБД (InnoDB vs PostgreSQL vs Cassandra).
· Проверить, что генерация UUID не станет узким местом (библиотеки умеют быстро).
· Согласовать с командой компромисс между равномерностью нагрузки и фрагментацией индекса.

Вывод: Выбор типа первичного ключа в распределённой системе — не деталь, а архитектурное решение. Автоинкремент убивает масштабируемость, случайный UUID — проверенный способ равномерно распределить нагрузку. Аналитик, знающий этот паттерн, спасает систему от «горячих точек» ещё на чертеже. 🎯

#DBMS
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
№4784 категория вопросов: #DBMS
4784. В отчёте при повторном запуске через секунду появились новые строки из-за параллельной вставки на уровне READ COMMITTED. Какой уровень изоляции гарантирует стабильность повторного чтения?
Anonymous Quiz
20%
READ UNCOMMITTED
19%
READ COMMITTED
42%
REPEATABLE READ
19%
SERIALIZABLE
Объяснение:

Суть проблемы

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

Что такое уровень изоляции SERIALIZABLE?

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

Почему не подходят другие варианты:

A (READ UNCOMMITTED) — разрешает грязное чтение (видны незафиксированные изменения), вообще не решает проблему.
B (READ COMMITTED) — предотвращает грязное чтение, но допускает неповторяемое чтение и фантомы.
C (REPEATABLE READ) — предотвращает неповторяемое чтение (те же строки не меняются), но некоторые СУБД (например, PostgreSQL) на этом уровне не предотвращают фантомы, если не используется SERIALIZABLE. В MySQL с InnoDB REPEATABLE READ предотвращает фантомы благодаря gap-блокировкам, но это особенность реализации. Стандарт SQL предписывает предотвращение фантомов только на уровне SERIALIZABLE.

Реальный кейс

В системе аналитики отчёты формировались на уровне изоляции READ COMMITTED. Бухгалтер запускал отчёт по выручке, смотрел цифры, через 5 минут перезапускал — сумма менялась на несколько тысяч. Причина: параллельно шли начисления бонусов и новые заказы. Переключили отчётные транзакции на SERIALIZABLE — результат стал стабильным в рамках сессии, но производительность упала из-за блокировок. Компромисс: пошли на ежечасное обновление материализованного представления вместо реального времени.

Что должен зафиксировать аналитик:

Для отчётов, требующих строгой согласованности (финансы, аудит) — указывать требование к уровню изоляции SERIALIZABLE или использовать механизм снэпшотов (MVCC).
Допустимость времени выполнения — SERIALIZABLE может быть медленнее из-за блокировок.
Альтернатива: выполнять отчёты на реплике в режиме READ ONLY с уровнем SERIALIZABLE или делать снимок данных (экспорт) на момент начала формирования отчёта.

Вывод: Выбор уровня изоляции влияет на согласованность и производительность. Аналитик должен требовать спецификации уровня изоляции для критичных отчётов, особенно в финансовой сфере. 🎯

#DBMS
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
№4785 категория вопросов: #SQL
4785. В таблице user_logins есть дубликаты. Нужно оставить только самый ранний вход для каждого пользователя в каждый день. Какой запрос это сделает?
Anonymous Quiz
13%
DELETE ... NOT IN (SELECT MIN(id) ...)
5%
DELETE с JOIN по времени
43%
WITH ranked AS (...) DELETE ... WHERE rn > 1
38%
DELETE с подзапросом > MIN(login_time)
Объяснение:

Задача: оставить одну запись на (user_id, день) — самую раннюю по времени.

Почему C — правильный?
Оконная функция ROW_NUMBER() нумерует строки внутри группы (user_id, день) в порядке возрастания login_time. Самый ранний вход получает номер 1. Затем удаляются все строки с номером больше 1 (rn > 1). Это стандартный, производительный и надёжный способ дедупликации, поддерживаемый всеми современными СУБД (PostgreSQL, MySQL 8+, SQL Server, Oracle).

Пример реального кода (вариант C):

```sql
WITH ranked AS (
SELECT id, user_id, login_time,
ROW_NUMBER() OVER (
PARTITION BY user_id, DATE(login_time)
ORDER BY login_time
) AS rn
FROM user_logins
)
DELETE FROM user_logins
WHERE (user_id, login_time) IN (
SELECT user_id, login_time FROM ranked WHERE rn > 1
);
```
Почему не подходят другие варианты:

A (NOT IN MIN(id)) — предполагает, что минимальный id соответствует самому раннему времени, но это не гарантировано (id может быть сгенерирован позже). Также NOT IN с подзапросом опасен при NULL и медленен на больших таблицах.

B (JOIN по времени) — может случайно удалить и самую раннюю запись, если существует более ранняя в тот же день. Синтаксис не универсален.

D (подзапрос > MIN) — некорректный синтаксис для массового удаления, выполняется построчно, очень медленно.
Реальный кейс:

В системе логов из-за ретраев образовались дубликаты: один пользователь в одну секунду имел несколько записей. Аналитик написал запрос с ROW_NUMBER() и удалил 8 млн дубликатов за 1 секунду. Вариант с NOT IN упал по таймауту.

Вывод для аналитика:
ROW_NUMBER() — ключевой инструмент для дедупликации, выбора первой/последней записи в группе. Это must-have в арсенале аналитика, работающего с SQL. 🎯

#SQL
Please open Telegram to view this post
VIEW IN TELEGRAM