Skip to content

Latest commit

 

History

History
801 lines (640 loc) · 72.1 KB

File metadata and controls

801 lines (640 loc) · 72.1 KB
layout ../../layouts/Layout.astro
title Базы данных
description Базы данных, проектирование схем, транзакции и SQL для подготовки к интервью
category Backend
kind questions
order 880

Базы данных

Основы и моделирование данных

Что такое БД?
  • База данных (БД / DB - Database): Это упорядоченная (структурированная) совокупность данных, организованная таким образом, чтобы обеспечить их удобное хранение, поиск, извлечение, обновление и управление.
  • Проще говоря: Это как электронная картотека или склад информации, где данные хранятся не хаотично, а по определенным правилам, что позволяет легко и быстро находить нужные сведения. Данные обычно хранятся в виде таблиц (в реляционных БД), документов, пар ключ-значение и т.д., в зависимости от типа БД.
  • Цель: Эффективное и надежное управление информацией для приложений, бизнес-процессов, анализа и т.д.
Что такое СУБД?
  • СУБД (Система Управления Базами Данных / DBMS - Database Management System): Это программное обеспечение (комплекс программ), которое позволяет пользователям и приложениям создавать, получать доступ, управлять и взаимодействовать с базами данных.
  • Функции СУБД:
    • Определение данных (создание структуры БД - таблицы, поля, типы данных).
    • Манипулирование данными (вставка, чтение, обновление, удаление - CRUD операции).
    • Управление доступом (безопасность, права пользователей).
    • Обеспечение целостности данных (соблюдение правил и ограничений).
    • Управление транзакциями (обеспечение ACID).
    • Резервное копирование и восстановление.
    • Управление параллельным доступом (чтобы несколько пользователей могли работать одновременно без конфликтов).
  • Примеры СУБД: PostgreSQL, MySQL, Oracle Database, Microsoft SQL Server, MongoDB, Redis, Cassandra.
  • Разница БД и СУБД: БД – это сами данные, СУБД – это программа для работы с этими данными.
Какие есть типы БД? С какими работал на практике?
  • Основные типы БД (по модели данных):

    1. Реляционные (SQL): Самый распространенный тип. Данные хранятся в виде таблиц (отношений), состоящих из строк и столбцов. Связи между таблицами устанавливаются с помощью ключей. Используют язык SQL.
      • Примеры СУБД: PostgreSQL, MySQL, Oracle, MS SQL Server, SQLite.
    2. Нереляционные (NoSQL - "Not Only SQL"): Группа различных типов БД, разработанных для решения задач, где реляционная модель менее эффективна (большие объемы данных, гибкая структура, высокая скорость).
      • Документо-ориентированные (Document): Хранят данные в виде документов (часто JSON или BSON), где каждый документ может иметь свою структуру. Хороши для полуструктурированных данных.
        • Примеры СУБД: MongoDB, Couchbase.
      • Ключ-значение (Key-Value): Простейший тип. Данные хранятся как набор пар: уникальный ключ и соответствующее ему значение. Очень быстрые для простых операций чтения/записи по ключу.
        • Примеры СУБД: Redis, Memcached.
      • Колоночные (Column-Family / Wide-Column): Данные хранятся по колонкам, а не по строкам. Эффективны для аналитических запросов, работающих с подмножеством колонок больших таблиц.
        • Примеры СУБД: Cassandra, HBase.
      • Графовые (Graph): Предназначены для хранения данных в виде узлов (вершин) и ребер (связей) между ними. Идеальны для моделирования сложных взаимосвязей (социальные сети, рекомендации, сети).
        • Примеры СУБД: Neo4j, ArangoDB.
    • (Устаревшие/Менее распространенные): Иерархические, Сетевые.
    • (Специализированные): Временных рядов (Time Series), Поисковые движки (Search Engines like Elasticsearch).
  • С какими работал (пример ответа): "В основном я работал с реляционными базами данных, чаще всего с PostgreSQL и MySQL, так как они используются в большинстве систем, где требуется структурированное хранение данных и транзакционная целостность. Также имел опыт работы с Redis (как Key-Value хранилищем) для задач кэширования и быстрой доставки некоторых данных. Поверхностно знакомился с MongoDB (как документной БД) на одном из проектов для хранения логов и пользовательских настроек с гибкой структурой."

Почему реляционные БД называют реляционными?
  • Реляционные базы данных называются так потому, что они основаны на реляционной модели данных, предложенной Эдгаром Коддом в 1970 году.
  • В основе этой модели лежит математическое понятие "отношение" (relation), которое в терминах БД представляет собой таблицу.
  • Таким образом, "реляционная" означает, что данные организованы в виде отношений (таблиц), состоящих из кортежей (строк/записей) и атрибутов (столбцов/полей). Связи между данными в разных таблицах также являются частью реляционной модели и реализуются через значения в столбцах (первичные и внешние ключи).
Какие задачи решаются с помощью нереляционных СУБД?

Нереляционные (NoSQL) СУБД хорошо подходят для решения задач, где традиционные реляционные БД могут испытывать трудности или быть неоптимальными:

  • Обработка больших объемов данных (Big Data): NoSQL системы часто лучше масштабируются горизонтально (добавлением новых серверов).
  • Высокая доступность и производительность: Многие NoSQL решения изначально проектировались для работы в распределенных системах с высокой нагрузкой на чтение/запись и устойчивостью к сбоям отдельных узлов.
  • Работа с неструктурированными и полуструктурированными данными: Документные БД (MongoDB) позволяют хранить данные с гибкой, изменяющейся схемой без необходимости заранее жестко определять все поля.
  • Кэширование данных: Key-Value хранилища (Redis, Memcached) идеально подходят для быстрого кэширования часто запрашиваемых данных в памяти.
  • Хранение данных сессий пользователей.
  • Обработка потоковых данных, логирование.
  • Хранение и анализ сложных взаимосвязей: Графовые БД (Neo4j) эффективны для анализа социальных связей, построения систем рекомендаций, обнаружения мошенничества.
  • Хранение каталогов товаров с разнообразными атрибутами.
В чем отличие реляционных и нереляционных БД? В каком виде хранятся данные в той или иной СУБД?
Признак Реляционные (SQL) Нереляционные (NoSQL)
Модель данных Таблицы (отношения) с строками и столбцами. Разнообразные: Документы, Ключ-Значение, Колоночные семьи, Графы.
Структура данных Жесткая, заранее определенная схема (Schema-on-Write). Гибкая, динамическая схема или без схемы (Schema-on-Read/Schemaless).
Хранение данных Таблицы: строки с фиксированным набором типизированных столбцов. Документы: JSON/BSON объекты.
Key-Value: Пары ключ-значение.
Колоночные: Таблицы с группами колонок.
Графы: Узлы и ребра с свойствами.
Масштабируемость Обычно вертикальная (увеличение мощности сервера). Горизонтальная сложнее. Обычно горизонтальная (добавление новых серверов, шардирование).
Язык запросов SQL (стандартизированный). Различные для каждого типа (API, специфичные языки запросов, иногда SQL-подобные).
Целостность данных Сильная согласованность (ACID транзакции). Часто ослабленная согласованность (BASE - Eventual Consistency) для доступности и производительности.
Связи между данными Явно определяются через внешние ключи (Foreign Keys). Реализуются по-разному: вложенные документы, прямые ссылки (ID), через логику приложения, явно в графовых БД.
Примеры СУБД PostgreSQL, MySQL, Oracle, MS SQL Server. MongoDB, Redis, Cassandra, Neo4j.
Что такое нормализация БД?
  • Нормализация: Это процесс организации данных в реляционной базе данных с целью уменьшения избыточности (дублирования) и улучшения целостности данных.
  • Цели нормализации:
    • Устранение аномалий вставки, обновления и удаления (проблем, возникающих из-за дублирования данных).
    • Минимизация объема хранимых данных.
    • Упрощение структуры БД и запросов на обновление.
    • Обеспечение логической целостности данных.
  • Процесс: Достигается путем декомпозиции (разделения) больших таблиц на меньшие, связанные между собой таблицы в соответствии с набором правил, называемых нормальными формами (НФ / NF).
Назови первые три нормальные формы
  1. Первая нормальная форма (1НФ / 1NF):
    • Правило: Все атрибуты (значения в ячейках таблицы) должны быть атомарными (неделимыми). То есть, в одной ячейке не может храниться список значений или вложенная таблица. Каждая строка должна быть уникальной (должен существовать первичный ключ).
    • Цель: Устранение повторяющихся групп и многозначных атрибутов.
  2. Вторая нормальная форма (2НФ / 2NF):
    • Правило: Таблица должна быть в 1НФ, и все неключевые атрибуты должны полностью зависеть от всего первичного ключа. Это актуально для таблиц с составным первичным ключом (из нескольких полей). Неключевой атрибут не должен зависеть только от части составного ключа.
    • Цель: Устранение частичных зависимостей.
  3. Третья нормальная форма (3НФ / 3NF):
    • Правило: Таблица должна быть в 2НФ, и не должно существовать транзитивных зависимостей неключевых атрибутов от первичного ключа. То есть, неключевой атрибут не должен зависеть от другого неключевого атрибута.
    • Цель: Устранение транзитивных зависимостей.

Есть и более высокие нормальные формы (Бойса-Кодда - BCNF, 4НФ, 5НФ), но на практике чаще всего достаточно достижения 3НФ или BCNF.

Что такое денормализация и когда ее использовать?
  • Денормализация: Это процесс, обратный нормализации, при котором в структуру базы данных намеренно вводится избыточность (дублирование данных) или объединяются таблицы.
  • Цель: Повышение производительности запросов на чтение (SELECT) за счет уменьшения количества соединений (JOIN) между таблицами. JOIN'ы могут быть дорогостоящими операциями на больших объемах данных.
  • Когда использовать:
    • Для оптимизации производительности: Когда строго нормализованная структура приводит к слишком медленным запросам (особенно в системах с высокой нагрузкой на чтение).
    • В хранилищах данных (DWH) и системах отчетности: Где скорость выполнения аналитических запросов важнее устранения избыточности, а данные обновляются реже. Часто используются схемы типа "звезда" или "снежинка", которые являются частично денормализованными.
    • Для упрощения запросов: В некоторых случаях денормализация может сделать запросы проще для написания и понимания.
  • Недостатки: Увеличение объема хранимых данных, усложнение операций обновления (нужно обновлять данные в нескольких местах), риск нарушения целостности данных, если обновления не синхронизированы. Требует осторожного применения.
Какие виды связей существуют в реляционных базах данных?

Между таблицами в реляционных БД существуют три основных вида связей, определяемых кардинальностью (мощностью):

  1. Один-к-одному (One-to-One / 1:1): Каждая запись в таблице A может быть связана не более чем с одной записью в таблице B, и наоборот.
    • Пример: Пользователи и ПрофилиПользователей (одному пользователю соответствует один профиль).
    • Реализация: Обычно через внешний ключ (Foreign Key) в одной из таблиц, который ссылается на первичный ключ (Primary Key) другой и имеет ограничение уникальности (UNIQUE), или через общий первичный ключ.
  2. Один-ко-многим (One-to-Many / 1:M): Каждая запись в таблице A (сторона "один") может быть связана с нулем, одной или несколькими записями в таблице B (сторона "многие"), но каждая запись в таблице B связана ровно с одной записью в таблице A.
    • Пример: Клиенты и Заказы (один клиент может иметь много заказов, но каждый заказ принадлежит одному клиенту).
    • Реализация: Внешний ключ в таблице B ("многие"), ссылающийся на первичный ключ таблицы A ("один"). Это самый распространенный тип связи.
  3. Многие-ко-многим (Many-to-Many / M:N): Каждая запись в таблице A может быть связана с нулем, одной или несколькими записями в таблице B, и наоборот, каждая запись в таблице B может быть связана с нулем, одной или несколькими записями в таблице A.
    • Пример: Студенты и Курсы (один студент может посещать много курсов, и один курс может посещать много студентов).
    • Реализация: Требует создания третьей, связующей (ассоциативной) таблицы (junction/linking table), которая содержит внешние ключи к обеим связываемым таблицам (A и B).
Каким образом осуществляется связь многие ко многим?

Связь "многие-ко-многим" (M:N) между двумя таблицами (например, TableA и TableB) реализуется с помощью промежуточной (связующей, ассоциативной) таблицы (например, TableA_TableB_Link).

  • Эта связующая таблица содержит как минимум два столбца:
    • Внешний ключ (ForeignKey_A), ссылающийся на первичный ключ TableA.
    • Внешний ключ (ForeignKey_B), ссылающийся на первичный ключ TableB.
  • Каждая строка в этой связующей таблице представляет собой одну конкретную связь между записью из TableA и записью из TableB.
  • Часто первичным ключом связующей таблицы является комбинация обоих внешних ключей (ForeignKey_A, ForeignKey_B).
  • В связующую таблицу также могут быть добавлены дополнительные атрибуты, характеризующие саму связь (например, в таблице Студент_Курс может быть поле ДатаЗачисления или Оценка).

Пример: Студенты (IDСтудента PK, Имя), Курсы (IDКурса PK, Название), Записи*на*курс (IDСтудента FK, IDКурса FK, Оценка).

Что такое первичный ключ и какими свойствами обладает?
  • Первичный ключ (Primary Key - PK): Это один или несколько столбцов в таблице реляционной БД, значения которых уникально идентифицируют каждую строку в этой таблице. Он служит основным идентификатором записи.
  • Свойства первичного ключа:
    1. Уникальность (Uniqueness): Значение первичного ключа должно быть уникальным для каждой строки таблицы. Не допускается наличие двух строк с одинаковым значением PK.
    2. Неизменяемость (Stability - желательно): Значение первичного ключа в идеале не должно изменяться после того, как строка была создана. Хотя технически некоторые СУБД позволяют это делать, это плохая практика, так как на PK могут ссылаться внешние ключи.
    3. Обязательность / Ненулевое значение (Non-Nullability): Первичный ключ не может содержать значение NULL. Каждая строка обязана иметь значение первичного ключа.
    4. Минимальность (для составных ключей): Если ключ составной (состоит из нескольких столбцов), то ни одно подмножество этих столбцов не должно обладать свойством уникальности само по себе.
  • Наличие первичного ключа обязательно для таблиц в нормализованной БД.
Что такое транзакция?
  • Транзакция: Это логическая единица работы, состоящая из одной или нескольких последовательных операций с базой данных (чтение, вставка, обновление, удаление), которая должна быть выполнена атомарно.
  • Атомарность означает: либо все операции внутри транзакции успешно выполняются и их результаты фиксируются в БД (commit), либо, если хотя бы одна операция не удалась или транзакция была отменена, ни одна из операций не должна повлиять на состояние БД, и система должна вернуться к состоянию до начала транзакции (rollback).
  • Цель: Обеспечение целостности и согласованности данных, особенно при одновременной работе нескольких пользователей или в случае сбоев.
  • Пример: Банковский перевод денег с одного счета на другой – это одна транзакция, включающая две операции: списание со счета А и зачисление на счет Б. Обе должны выполниться успешно, иначе обе должны быть отменены.
Что такое требования ACID?

ACID – это акроним, описывающий четыре ключевых свойства, гарантирующих надежность транзакций в СУБД:

  1. Atomicity (Атомарность): Транзакция выполняется как единое целое: либо все её операции успешно завершаются, либо ни одна из них не выполняется (происходит откат). "Всё или ничего".
  2. Consistency (Согласованность): Транзакция переводит базу данных из одного согласованного (валидного) состояния в другое согласованное состояние. Все правила целостности БД (ограничения, ключи) должны соблюдаться как до, так и после транзакции.
  3. Isolation (Изолированность): Параллельно выполняющиеся транзакции не должны влиять друг на друга. Результаты промежуточных операций одной транзакции не видны другим транзакциям до её завершения (commit). Существуют разные уровни изоляции, определяющие степень влияния транзакций друг на друга.
  4. Durability (Стойкость / Долговечность): Если транзакция успешно завершена (commit), то все сделанные ею изменения являются постоянными и не будут потеряны даже в случае сбоев системы (например, отказ питания или перезагрузка).

ACID-свойства являются стандартом для большинства реляционных СУБД.

Как происходит процесс проектирования БД?

Проектирование БД – это итеративный процесс, обычно включающий следующие этапы:

  1. Сбор и анализ требований: Понимание того, какие данные необходимо хранить, как они будут использоваться, какие бизнес-правила и ограничения существуют. Взаимодействие со стейкхолдерами, анализ предметной области.
  2. Концептуальное проектирование: Создание высокоуровневой модели данных, независимой от конкретной СУБД. Определение основных сущностей (Entities), их атрибутов и связей между ними. Часто используется ER-диаграмма (Entity-Relationship Diagram).
  3. Логическое проектирование: Преобразование концептуальной модели в логическую модель, соответствующую выбранному типу СУБД (например, реляционной). Определение таблиц, столбцов, типов данных, первичных и внешних ключей. Применение нормализации для устранения избыточности и аномалий. Уточнение связей.
  4. Физическое проектирование: Адаптация логической модели к конкретной СУБД и среде эксплуатации. Выбор типов данных с учетом СУБД, определение индексов, стратегий хранения, партиционирования (если нужно), настройка параметров производительности и безопасности.
  5. Реализация: Создание схемы БД с использованием SQL (DDL команды: CREATE TABLE, ALTER TABLE и т.д.).
  6. Тестирование и наполнение данными: Проверка корректности структуры, загрузка начальных данных.
  7. Эксплуатация и оптимизация: Мониторинг производительности, внесение изменений в структуру по мере необходимости (рефакторинг, добавление индексов, денормализация и т.д.).
Какие способы оптимизации БД можешь назвать?

Оптимизация БД направлена на повышение скорости выполнения запросов и эффективности использования ресурсов. Основные способы:

  • Индексирование: Создание индексов на столбцах, часто используемых в условиях WHERE, JOIN, ORDER BY, GROUP BY. Правильный выбор типов индексов (B-tree, Hash, Full-text...). Удаление неиспользуемых индексов.
  • Оптимизация запросов:
    • Написание эффективного SQL-кода (избегать SELECT *, использовать LIMIT, выбирать нужные поля).
    • Анализ планов выполнения запросов (EXPLAIN, EXPLAIN ANALYZE) для выявления узких мест.
    • Переписывание неэффективных запросов (использование правильных JOIN'ов, избегание коррелирующих подзапросов там, где можно).
    • Использование параметризованных запросов.
  • Оптимизация схемы БД:
    • Нормализация (для устранения избыточности и аномалий).
    • Денормализация (для ускорения чтения там, где это оправдано).
    • Выбор оптимальных типов данных (использовать наиболее подходящий и наименьший возможный тип).
    • Использование ограничений (constraints) для поддержания целостности.
  • Конфигурация сервера СУБД: Настройка параметров СУБД (размеры буферов, кэшей, количество соединений и т.д.) в соответствии с нагрузкой и аппаратными ресурсами.
  • Аппаратное обеспечение: Увеличение ОЗУ, использование быстрых дисков (SSD), мощные процессоры.
  • Кэширование: Кэширование результатов частых и дорогих запросов на уровне приложения или с использованием специализированных инструментов (Redis, Memcached).
  • Партиционирование / Шардирование / Репликация: (см. следующие вопросы).
  • Регулярное обслуживание: Обновление статистики таблиц (для оптимизатора запросов), реиндексация, очистка (vacuuming в PostgreSQL).
Что такое партиционирование и по какому принципу оно реализовывается?
  • Партиционирование (Partitioning): Это процесс разделения одной большой логической таблицы (или индекса) на несколько меньших физических частей (партиций), которые хранятся отдельно, но для пользователя/приложения остаются видимыми как единое целое. Партиционирование выполняется внутри одного экземпляра (сервера) СУБД.
  • Цели:
    • Улучшение производительности: Запросы, обращающиеся к данным только в одной или нескольких партициях, выполняются быстрее, так как сканируется меньший объем данных.
    • Упрощение управления: Операции обслуживания (архивирование, удаление старых данных, резервное копирование) можно выполнять на уровне отдельных партиций, что быстрее и менее ресурсоемко.
    • Повышение доступности: Сбой при работе с одной партицией может не затронуть остальные.
  • Принципы (методы) партиционирования: Определяют, как строки распределяются по партициям на основе значения ключа партиционирования:
    • По диапазону (Range Partitioning): Данные распределяются на основе попадания значения ключа в определенный непрерывный диапазон (например, по дате: партиция для января, партиция для февраля и т.д.; по ID заказа). PARTITION BY RANGE (order_date)
    • По списку (List Partitioning): Данные распределяются на основе принадлежности значения ключа к заданному списку дискретных значений (например, по коду региона, статусу заказа). PARTITION BY LIST (country_code)
    • По хэшу (Hash Partitioning): Данные распределяются на основе значения хэш-функции, примененной к ключу партиционирования. Обеспечивает равномерное распределение, но менее интуитивно для запросов по диапазонам. PARTITION BY HASH (user_id)
    • (Композитное): Комбинация нескольких методов (например, партиционирование по диапазону дат, а внутри каждой даты – по хэшу от ID пользователя).
Что такое реплицирование?
  • Репликация (Replication): Это процесс создания и синхронизации точных копий (реплик) базы данных (или её части) на одном или нескольких других серверах.
  • Цели:
    • Повышение отказоустойчивости и доступности: Если основной сервер (мастер/primary) выходит из строя, один из серверов-реплик может взять на себя его роль (failover), минимизируя простой.
    • Распределение нагрузки (Read Scalability): Запросы на чтение можно направлять на серверы-реплики, снижая нагрузку на основной сервер, который обрабатывает операции записи.
    • Резервное копирование: Реплики можно использовать для создания бэкапов без остановки основного сервера.
    • Географическое распределение: Размещение реплик ближе к пользователям для уменьшения задержек при чтении.
  • Типы: Бывает синхронная (изменения подтверждаются после записи на реплику) и асинхронная (изменения сначала пишутся на мастер, потом передаются на реплику - возможна небольшая задержка). Основные архитектуры: мастер-реплика (master-slave), мастер-мастер (реже, сложнее).
Что такое шардирование?
  • Шардирование (Sharding): Это техника горизонтального масштабирования базы данных, при которой большая база данных разделяется на более мелкие, независимые части (шарды), и эти части распределяются по разным серверам (узлам). Каждый шард содержит уникальный поднабор данных всей БД.
  • Цели:
    • Масштабирование записи и чтения: Распределение нагрузки по нескольким серверам позволяет обрабатывать гораздо больший объем данных и количество запросов, чем может выдержать один сервер.
    • Управление очень большими БД: Позволяет хранить объемы данных, превышающие емкость одного сервера.
  • Принцип: Данные распределяются по шардам на основе ключа шардирования (sharding key). Требуется механизм (в приложении или специальный прокси/роутер) для определения, на каком шарде находятся нужные данные, и направления запроса на соответствующий сервер.
  • Сложности: Запросы, затрагивающие данные на нескольких шардах (cross-shard queries, joins), становятся сложными и медленными. Сложность управления и обеспечения согласованности.
Чем отличается реплицирование и шардирование?
Признак Репликация Шардирование
Цель Отказоустойчивость, доступность, масштабирование чтения. Масштабирование записи и чтения, обработка огромных объемов данных.
Данные Копии одних и тех же данных на разных серверах. Уникальные части (подмножества) данных на разных серверах.
Структура Несколько серверов хранят (в идеале) полный набор данных. Несколько серверов, каждый хранит свою часть общего набора данных.
Масштабирование В основном улучшает чтение. Ограниченно для записи (все пишут на мастер). Улучшает и чтение, и запись, распределяя их по шардам.
Сложность запросов Запросы обычно не усложняются. Запросы, затрагивающие несколько шардов, усложняются.
Основная проблема Синхронизация копий, возможные задержки. Маршрутизация запросов, межшардовые операции.

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

Что такое маппинг данных?
  • Маппинг данных (Data Mapping): Это процесс установления соответствия (связывания) между элементами данных из двух различных источников или моделей данных. Он определяет, как данные из одного источника преобразуются и переносятся в другой.
  • Где используется:
    • Интеграция данных: При объединении данных из разных систем (например, CRM и ERP).
    • Миграция данных: При переносе данных из старой системы в новую.
    • Хранилища данных (ETL/ELT): При загрузке данных из операционных систем в DWH.
    • Интеграция через API: При передаче данных между сервисами.
    • ORM (Object-Relational Mapping): Специфический вид маппинга между объектами в коде приложения и таблицами в реляционной БД.
  • Процесс: Включает определение полей-источников, полей-приемников и правил трансформации (изменение формата, объединение/разделение полей, применение формул и т.д.). Результатом часто является документ или таблица маппинга.
Какой уровень абстракции знаешь? В чем отличия?

Речь идет о трехуровневой архитектуре ANSI-SPARC, описывающей три уровня представления данных в СУБД для обеспечения независимости данных:

  1. Внешний уровень (External Level / View Level):
    • Описание: Представление данных для конкретных пользователей или приложений. Определяет, какую часть БД видит пользователь и в каком виде. Может быть несколько внешних представлений для одной БД.
    • Реализация: Через представления (Views), которые скрывают детали нижележащих уровней и могут предоставлять данные в удобном формате, а также обеспечивать безопасность (ограничивать доступ к определенным строкам/столбцам).
    • Цель: Удобство пользователя, безопасность.
  2. Концептуальный уровень (Conceptual Level / Logical Level):
    • Описание: Общее, полное представление структуры всей базы данных для сообщества пользователей. Описывает сущности, атрибуты, связи, ограничения целостности, независимо от того, как данные физически хранятся.
    • Реализация: Логическая схема БД (например, набор CREATE TABLE и CONSTRAINT без учета индексов и файлов).
    • Цель: Описание семантики данных, обеспечение логической независимости данных (изменения на физическом уровне не влияют на концептуальный).
  3. Внутренний уровень (Internal Level / Physical Level):
    • Описание: Представление физического хранения данных на носителях. Описывает структуры данных (файлы, страницы), методы доступа, индексы, организацию записей, сжатие, шифрование.
    • Реализация: Зависит от конкретной СУБД.
    • Цель: Эффективное хранение и доступ к данным, обеспечение физической независимости данных (изменения на внутреннем уровне, например, добавление индекса, не должны влиять на концептуальный и внешний уровни).

Отличия: Уровни предоставляют разную степень абстракции от деталей хранения и структуры данных, обеспечивая независимость данных и удобство для разных ролей (пользователь, разработчик, администратор БД).

Зачем нужны индексы в таблицах БД? Встречал ли на практике?
  • Зачем нужны индексы: Индексы – это специальные структуры данных (чаще всего B-деревья), которые создаются для одного или нескольких столбцов таблицы с целью значительного ускорения операций поиска и извлечения данных (SELECT).
  • Как работают (аналогия): Подобно предметному указателю в конце книги, индекс позволяет СУБД быстро находить строки с нужными значениями в индексированных столбцах, не сканируя всю таблицу целиком (что может быть очень долго для больших таблиц).
  • Когда особенно полезны:
    • Для столбцов, часто используемых в условии WHERE.
    • Для столбцов, используемых в операциях соединения JOIN.
    • Для столбцов, используемых для сортировки ORDER BY.
  • Недостатки:
    • Занимают дополнительное место на диске.
    • Замедляют операции изменения данных (INSERT, UPDATE, DELETE), так как при изменении данных в таблице нужно обновлять и сам индекс.
  • Встречал ли на практике: "Да, безусловно. Индексы – это один из первых и самых эффективных инструментов оптимизации производительности БД. Я неоднократно сталкивался с ситуациями, когда запросы к большим таблицам выполнялись очень медленно (секунды или даже минуты), и добавление правильного индекса на столбцы в WHERE или JOIN сокращало время выполнения до долей секунды. Также видел обратные ситуации, когда избыточные или неиспользуемые индексы замедляли операции записи и занимали лишнее место."
Что такое грязное чтение в БД?
  • Грязное чтение (Dirty Read): Это одна из аномалий параллельного доступа к данным в БД, возникающая при низких уровнях изоляции транзакций (например, Read Uncommitted).
  • Суть: Транзакция A читает данные, которые были изменены транзакцией B, но еще не были зафиксированы (commit) транзакцией B.
  • Проблема: Если транзакция B после этого будет отменена (rollback), то данные, прочитанные транзакцией A, окажутся неверными, "грязными", так как они никогда не существовали в БД в зафиксированном виде. Это может привести к некорректным решениям или результатам на основе этих неверных данных.
  • Более высокие уровни изоляции (Read Committed, Repeatable Read, Serializable) предотвращают грязное чтение.

SQL

Какие знаешь команды SQL? Насколько сложные запросы пишешь?
  • Команды SQL (по категориям):

    • DDL (Data Definition Language) - Язык определения данных:
      • CREATE: Создание объектов БД (DATABASE, TABLE, INDEX, VIEW, FUNCTION, PROCEDURE...).
      • ALTER: Изменение структуры существующих объектов (TABLE - добавить/удалить/изменить столбец, ограничение...).
      • DROP: Удаление объектов БД.
    • DML (Data Manipulation Language) - Язык манипулирования данными:
      • SELECT: Извлечение данных из таблиц.
      • INSERT: Вставка новых строк в таблицу.
      • UPDATE: Обновление существующих строк в таблице.
      • DELETE: Удаление строк из таблицы.
    • DCL (Data Control Language) - Язык управления данными:
      • GRANT: Предоставление прав доступа пользователям.
      • REVOKE: Отзыв прав доступа.
    • TCL (Transaction Control Language) - Язык управления транзакциями:
      • COMMIT: Фиксация транзакции.
      • ROLLBACK: Откат транзакции.
      • SAVEPOINT: Установка точки сохранения внутри транзакции.
  • Насколько сложные запросы пишешь (пример ответа): "Я уверенно владею всеми основными командами DML, особенно SELECT. Регулярно пишу запросы с использованием:

    • Различных типов JOIN (INNER, LEFT, RIGHT, иногда FULL OUTER).
    • Фильтрации WHERE с разнообразными условиями (сравнения, LIKE, IN, BETWEEN, IS NULL, логические операторы AND/OR/NOT).
    • Агрегатных функций (COUNT, SUM, AVG, MIN, MAX) с группировкой GROUP BY.
    • Фильтрации агрегированных данных с помощью HAVING.
    • Сортировки ORDER BY.
    • Подзапросов (в SELECT, FROM, WHERE).
    • Оконных функций (ROW_NUMBER, RANK, DENSE_RANK, агрегатные функции с OVER(...)).
    • Общих табличных выражений (Common Table Expressions - WITH...AS). При необходимости могу анализировать план выполнения запроса (EXPLAIN) для поиска путей оптимизации. С DDL командами (CREATE TABLE, ALTER TABLE) также знаком на уровне, необходимом для понимания структуры данных и внесения простых изменений."
Что такое JOIN-запросы и как какие они бывают?
  • JOIN-запросы: Это операторы SQL, используемые для объединения строк из двух или более таблиц на основе связанного столбца (условия соединения) между ними. Они позволяют извлекать данные из нескольких таблиц как единое целое.
  • Основные типы JOIN:
    1. INNER JOIN (Внутреннее соединение): Возвращает только те строки, для которых есть совпадение в обеих соединяемых таблицах по условию ON. (Пересечение множеств).
    2. LEFT JOIN (или LEFT OUTER JOIN - Левое внешнее соединение): Возвращает все строки из левой таблицы и соответствующие им строки из правой таблицы. Если для строки из левой таблицы нет совпадения в правой, то столбцы правой таблицы будут заполнены значениями NULL.
    3. RIGHT JOIN (или RIGHT OUTER JOIN - Правое внешнее соединение): Возвращает все строки из правой таблицы и соответствующие им строки из левой таблицы. Если для строки из правой таблицы нет совпадения в левой, то столбцы левой таблицы будут заполнены значениями NULL. (Работает зеркально LEFT JOIN).
    4. FULL OUTER JOIN (Полное внешнее соединение): Возвращает все строки из обеих таблиц. Если для строки из одной таблицы нет совпадения в другой, то столбцы недостающей таблицы заполняются NULL. (Объединение множеств).
    5. CROSS JOIN (Перекрестное соединение): Возвращает декартово произведение строк из обеих таблиц (каждая строка первой таблицы соединяется с каждой строкой второй таблицы). Обычно используется без условия ON. Применяется редко в аналитических задачах.
    6. Self JOIN (Соединение таблицы с собой): Техника, когда таблица соединяется сама с собой с использованием псевдонимов (aliases), чтобы найти связи между строками внутри одной таблицы (например, найти сотрудников и их менеджеров в одной таблице Employees).
Чем TRUNCATE отличается от DELETE?

Хотя обе команды удаляют строки из таблицы, они работают по-разному и имеют разные характеристики:

Характеристика DELETE FROM table_name [WHERE condition]; TRUNCATE TABLE table_name;
Тип команды DML (Data Manipulation Language) DDL (Data Definition Language)
Удаление строк Удаляет строки по одной, соответствующие условию WHERE (или все, если WHERE нет). Удаляет все строки из таблицы сразу, обычно через освобождение страниц данных.
Условие WHERE Можно использовать для выборочного удаления. Нельзя использовать. Удаляет только все строки.
Скорость Медленнее (особенно для больших таблиц). Значительно быстрее.
Логирование Обычно логирует удаление каждой строки. Логирует минимально (например, деаллокацию страниц).
Триггеры Активирует ON DELETE триггеры. Обычно не активирует триггеры.
Откат (Rollback) Можно откатить в рамках транзакции. Зависит от СУБД, часто нельзя откатить или требует специальных настроек.
Счетчики (Auto Increment) Обычно не сбрасывает. Обычно сбрасывает к начальному значению.
Права доступа Требует прав DELETE на таблицу. Требует более высоких прав (часто ALTER или TRUNCATE).

Итог: DELETE – для выборочного или полного удаления с возможностью отката и активацией триггеров. TRUNCATE – для очень быстрого полного опустошения таблицы без возможности отката (часто) и без триггеров.

Для чего используется HAVING в SQL?
  • Предложение HAVING используется для фильтрации результатов запроса после того, как строки были сгруппированы с помощью GROUP BY и для них были вычислены агрегатные функции (COUNT, SUM, AVG, MIN, MAX и т.д.).
  • Он позволяет задать условие на значения агрегатных функций для групп строк.
Чем отличается HAVING от WHERE?
Характеристика WHERE HAVING
На что применяется Фильтрует отдельные строки. Фильтрует группы строк.
Когда применяется До группировки (GROUP BY). После группировки (GROUP BY).
Работа с агрегатами Не может содержать агрегатные функции (кроме как в подзапросах). Может (и обычно содержит) агрегатные функции.
Порядок выполнения (лог.) FROM -> WHERE -> GROUP BY -> HAVING FROM -> WHERE -> GROUP BY -> HAVING

Проще говоря: WHERE фильтрует строки до того, как они попадут в "котел" агрегации, а HAVING фильтрует уже результаты этого "котла" (сгруппированные строки).

Назовите все способы в SQL выбрать данные из первой таблицы, которых нет во второй таблице

Пусть есть TableA и TableB со столбцом id, по которому их можно связать. Нужно выбрать строки из TableA, для которых нет соответствующих id в TableB.

  1. LEFT JOIN с проверкой на NULL (самый распространенный):

    SELECT A.*
    FROM TableA A
    LEFT JOIN TableB B ON A.id = B.id
    WHERE B.id IS NULL;

    Принцип: Присоединяем B к A. Если для строки из A нет соответствия в B, поля из B будут NULL. Фильтруем по этому NULL.

  2. Подзапрос с NOT EXISTS (часто эффективный и читаемый):

    SELECT A.*
    FROM TableA A
    WHERE NOT EXISTS (
        SELECT 1 -- или любое другое значение/столбец
        FROM TableB B
        WHERE B.id = A.id
    );

    Принцип: Для каждой строки A проверяем, существует ли хотя бы одна строка в B с таким же id. Если не существует, строка A включается в результат.

  3. Подзапрос с NOT IN (может быть менее эффективным, осторожно с NULL):

    SELECT A.*
    FROM TableA A
    WHERE A.id NOT IN (
        SELECT B.id
        FROM TableB B
        WHERE B.id IS NOT NULL -- Важно исключить NULL из подзапроса!
    );

    Принцип: Выбираем все id из B, а затем выбираем строки из A, id которых нет в этом списке. Важно: Если подзапрос SELECT B.id FROM TableB B вернет хотя бы одно значение NULL, то NOT IN не вернет ни одной строки (или поведет себя непредсказуемо, в зависимости от СУБД). Поэтому часто добавляют WHERE B.id IS NOT NULL.

  4. Оператор EXCEPT (SQL Standard) или MINUS (Oracle) (если нужно вернуть только общие поля):

    -- SQL Standard
    SELECT id FROM TableA
    EXCEPT
    SELECT id FROM TableB;
    
    -- Oracle
    SELECT id FROM TableA
    MINUS
    SELECT id FROM TableB;

    Принцип: Возвращает все строки из первого запроса, которых нет во втором запросе (вычитание множеств). Обычно возвращает только столбцы, указанные в SELECT.

Чем отличается UNION от UNION ALL?

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

  • UNION:
    • Объединяет результаты запросов.
    • Удаляет дублирующиеся строки из итогового набора.
    • Требует дополнительной операции сортировки/сравнения для выявления дубликатов, поэтому может быть медленнее.
  • UNION ALL:
    • Объединяет результаты запросов.
    • Оставляет все строки, включая дубликаты.
    • Не выполняет проверку на дубликаты, поэтому обычно быстрее, чем UNION.

Когда использовать:

  • Используйте UNION, если вам нужен набор уникальных строк.
  • Используйте UNION ALL, если дубликаты допустимы или вы уверены, что их не будет, и важна производительность.

Эти ответы охватывают ключевые аспекты баз данных и SQL для собеседования аналитика. Удачи!