4670. В системе электронного документооборота у сущности «Договор» есть несколько взаимозависимых статусов: status_system, status_lega, status_financial. Как лучше смоделировать это в БД, чтобы легко добавлять новые аспекты статусов?
Anonymous Quiz
4%
Хранить все в одном поле status типа VARCHAR со значением, например, "active_approved_paid".
53%
Создать отдельную таблицу со связью «многие-ко-многим» к справочнику возможных статусов.
28%
Использовать несколько BOOLEAN полей или ENUM/маленьких INT для каждого независимого аспекта.
16%
Хранить статус как JSONB, где ключами будут аспекты: {"system": "active", "legal": "approved"}.
👩🏫Объяснение:
Независимые логические атрибуты (аспекты статуса) лучше хранить в отдельных колонках. Это дает максимальную простоту и эффективность: фильтрация (WHERE status_legal = 'approved') и индексация по каждому аспекту тривиальны, целостность данных легко контролируется. Хранение в одной строке (A) делает запросы неэффективными. Связь многие-ко-многим (B) избыточна для простых атрибутов. JSONB (D) гибок, но сложнее в валидации и обычно медленнее для частой фильтрации. Подход C следует принципу «одна колонка — один атомарный факт».
После обновления приложения в продекшене появилась ошибка, из-за которой в таблицу записывались платежи с нулевой суммой. Ошибку исправили. Как безопасно удалить ~10 000 некорректных записей из таблицы с 50 миллионами строк, не нарушая работу операций?
Anonymous Quiz
28%
Выполнить DELETE FROM payments WHERE amount = 0 AND created_at > ...
34%
Скопировать корректные данные во временную таблицу, сделать rename, пересоздать индексы в фоне.
32%
Пометить записи как удаленные, а физически удалить ночью.
6%
Использовать логическое удаление и фильтровать на уровне приложения.
👩🏫Объяснение:
На самом деле, для удаления 10к строк из 50 млн можно смело использовать осторожный DELETE с ограничением по времени (A), выполнив его в периоды низкой нагрузки, возможно, батчами (LIMIT 1000), чтобы не блокировать таблицу надолго. Однако, если бы речь шла об удалении миллионов строк, то вариант B (создание новой таблицы) был бы предпочтительнее, так как DELETE при огромном объеме — долгая, тяжелая операция, генерирующая много WAL-логов и потенциально блокирующая. Варианты C и D не очищают данные, а лишь маскируют проблему. В реалистичном кейсе с 10к записей правильнее A, но понимание альтернативы B для больших объемов — ключевое.
4674. Вы проектируете аналитическую систему для ритейла, где ключевые отчеты строятся по итогам дня, недели, месяца. Какой наиболее правильный и распространенный архитектурный подход?
Anonymous Quiz
16%
Реплицировать OLTP-базу на отдельный сервер и выполнять запросы там.
16%
Настроить индексы в операционной БД так, чтобы они покрывали все аналитические запросы.
56%
Реализовать механизм ETL, который будет переносить и преобразовывать данные в отдельное хранилище.
11%
Выполнять агрегации в реальном времени, используя кэширующий слой с предвычисленными значениями.
👩🏫Объяснение:
Это классический паттерн разделения на OLTP (операционная обработка транзакций) и OLAP (аналитическая обработка). Прямые аналитические запросы к OLTP-системе (A, B) блокируют операционные транзакции и убивают производительность. ETL-процесс (C) переносит данные в специально спроектированное хранилище (DWH), где данные денормализованы, структурированы по темам (схема «звезда»/«снежинка») и используют эффективные для чтения форматы хранения (колоночные СУБД). Кэш (D) хорош для простых метрик, но не для гибкой, многомерной аналитики.
4675. В таблице documents есть поле version (целое число). Как должен выглядеть SQL-запрос для обновления документа, который гарантированно предотвратит «потерянное обновление» (lost update), если два пользователя редактируют один документ?
Anonymous Quiz
22%
UPDATE documents SET content='новый текст', version = version + 1 WHERE id = 123;
48%
UPDATE documents SET content='новый текст', version = version + 1 WHERE id = 123 AND version
21%
SELECT ... FOR UPDATE; затем UPDATE documents ... WHERE id=123;
10%
UPDATE documents SET content='новый текст' WHERE id = 123;
👩🏫Объяснение:
Суть оптимистичной блокировки — позволить всем читать данные, но проверять, изменились ли они с момента чтения, в момент записи. Ключевой элемент — проверка версии в условии WHERE. Если другой процесс уже успел обновить документ, то его version изменился, и запрос текущего процесса (B) не затронет ни одной строки (affected rows = 0). Приложение, увидев 0 измененных строк, поймет, что произошел конфликт и должно предложить пользователю разрешить его. Вариант A увеличит версию всегда, потеряв первое обновление. Вариант C — это пессимистическая блокировка. Вариант D не использует версионирование вовсе.
4676. Требуется сложная морфология, ранжирование по релевантности, фасетный поиск и отказоустойчивость. Какое решение является индустриальным стандартом?
Anonymous Quiz
9%
Перейти на более мощный сервер БД с большим объемом RAM.
16%
Реализовать кастомную логику поиска на стороне приложения, используя кэш.
66%
Использовать выделенную поисковую систему, такую как Elasticsearch или Apache Solr.
9%
Переписать все запросы, максимально их оптимизировав и добавив больше составных индексов.
👩🏫Объяснение:
Когда требования к поиску выходят за рамки базовых возможностей реляционных СУБД, используется специализированный поисковый движок. Elasticsearch/Solr построены на инвертированных индексах, созданных именно для задач:
* Полнотекстового поиска со стеммингом, синонимами, обработкой омонимов.
* Нечеткого поиска (fuzzy).
* Сложного ранжирования (relevance scoring) на основе TF-IDF, BM25.
* Масштабирования и отказоустойчивости за счет распределенной кластеризации.
«Подкручивание» существующей БД (A, D) дает лишь временный и ограниченный эффект. Кастомная реализация (B) неоправданно сложна и не будет соответствовать по качеству и производительности готовым решениям.
* Полнотекстового поиска со стеммингом, синонимами, обработкой омонимов.
* Нечеткого поиска (fuzzy).
* Сложного ранжирования (relevance scoring) на основе TF-IDF, BM25.
* Масштабирования и отказоустойчивости за счет распределенной кластеризации.
«Подкручивание» существующей БД (A, D) дает лишь временный и ограниченный эффект. Кастомная реализация (B) неоправданно сложна и не будет соответствовать по качеству и производительности готовым решениям.
4677. Таблица votes потенциально может расти на миллиарды строк. Критически важна скорость проверки, голосовал ли пользователь. Какой первичный ключ для таблицы votes будет оптимальным?
Anonymous Quiz
15%
id BIGSERIAL PRIMARY KEY (автоинкремент).
42%
Составной первичный ключ (user_id, entity_type, entity_id).
20%
PRIMARY KEY (entity_type, entity_id, user_id).
23%
uuid PRIMARY KEY.
👩🏫Объяснение:
Здесь важны две вещи: гарантия уникальности комбинации «пользователь-сущность» и скорость проверки этой уникальности при вставке. Составной первичный ключ (user_id, entity_type, entity_id) (B) идеально решает обе задачи:
1. Он на уровне БД гарантирует, что дубликат невозможен.
2. Запрос SELECT 1 FROM votes WHERE user_id = ? AND entity_type = ? AND entity_id = ? для проверки будет выполняться очень быстро, используя поиск по первичному ключу (т.е. по кластеризованному индексу).
Порядок колонок важен: если чаще проверяют по user_id, он должен быть первым. Ключ из варианта C тоже рабочий, но оптимизирован для поиска всех голосов за сущность, что менее частый сценарий. Автоинкремент (A) и UUID (D) не предотвращают дублирование логических записей без отдельного UNIQUE-ограничения.
1. Он на уровне БД гарантирует, что дубликат невозможен.
2. Запрос SELECT 1 FROM votes WHERE user_id = ? AND entity_type = ? AND entity_id = ? для проверки будет выполняться очень быстро, используя поиск по первичному ключу (т.е. по кластеризованному индексу).
Порядок колонок важен: если чаще проверяют по user_id, он должен быть первым. Ключ из варианта C тоже рабочий, но оптимизирован для поиска всех голосов за сущность, что менее частый сценарий. Автоинкремент (A) и UUID (D) не предотвращают дублирование логических записей без отдельного UNIQUE-ограничения.
4678. Вы обнаружили, что в таблице events с временными рядами 99% запросов обращаются только к данным за последние 7 дней. Таблица содержит данные за 5 лет. Какое изменение структуры хранения даст максимальный эффект ?
Anonymous Quiz
62%
Создать партиционирование таблицы по диапазону дат (например, по дням или неделям).
14%
Добавить индекс на поле с датой, включив в него все часто запрашиваемые колонки.
3%
Запустить процедуру полной перестройки (REINDEX) всех индексов таблицы.
21%
Регулярно (раз в неделю) удалять старые данные, перемещая их в архивную таблицу.
👩🏫Объяснение:
Партиционирование — наиболее фундаментальное и эффективное решение для временных рядов с ярко выраженным паттерном доступа к «горячим» (свежим) данным. Оно позволяет:
* Резко уменьшить объем сканируемых данных: оптимизатор запросов будет обращаться только к партициям за последние 7 дней (партициональная прунинг).
* Упростить управление жизненным циклом: удаление старых данных (DROP PARTITION) — мгновенная и дешевая операция.
* Улучшить производительность обслуживания: операции VACUUM, REINDEX можно выполнять точечно на устаревших партициях.
Создание покрывающего индекса (B) или его перестройка (C) могут помочь, но не решат проблему работы с огромной неделимой таблицей. Ручное перемещение данных (D) — это, по сути, «ручное» партиционирование, но менее эффективное и встроенное в СУБД.
* Резко уменьшить объем сканируемых данных: оптимизатор запросов будет обращаться только к партициям за последние 7 дней (партициональная прунинг).
* Упростить управление жизненным циклом: удаление старых данных (DROP PARTITION) — мгновенная и дешевая операция.
* Улучшить производительность обслуживания: операции VACUUM, REINDEX можно выполнять точечно на устаревших партициях.
Создание покрывающего индекса (B) или его перестройка (C) могут помочь, но не решат проблему работы с огромной неделимой таблицей. Ручное перемещение данных (D) — это, по сути, «ручное» партиционирование, но менее эффективное и встроенное в СУБД.