Как стать автором
Обновить
522.67
OTUS
Цифровые навыки от ведущих экспертов

О граблях в архитектуре баз данных

Уровень сложностиПростой
Время на прочтение7 мин
Количество просмотров4.1K

В предыдущей статье мы говорили о тех ошибках, которые допускают начинающие администраторы при работе с PostgreSQL. А сейчас мы рассмотрим те грабли, на которые могут наступить начинающие архитекторы при построении структуры баз данных. Начнем с первичных ключей.

Первичный ключ как основа

Для начала давайте разберемся с тем, что такое первичный ключ (primary key). В PostgreSQL первичный ключ — это столбец (или набор столбцов), который однозначно идентифицирует каждую строку в таблице. Он необходим для обеспечения целостности данных и играет важную роль в нормализации БД. Значение первичного ключа должно быть уникальным для каждой строки в таблице и первичный ключ не может иметь значение NULL. Каждая таблица может иметь только один первичный ключ.

PostgreSQL, как и многие другие СУБД, автоматически создаёт индекс для столбцов Primary key, что позволяет быстро извлекать данные и фильтровать их на основе первичного ключа.

Для первичных ключей PostgreSQL поддерживает несколько типов данных, среди них:

  • Serial. Автоматически увеличивающийся целочисленный тип, который часто выбирают для первичных ключей.

  • UUID. Универсально уникальный идентификатор, который часто используют, когда порядок значений первичного ключа не важен.

  • Составные первичные ключи. Комбинация нескольких столбцов, которые вместе однозначно идентифицируют каждую строку.

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

Потерянный ключ

Многие начинающие разработчики БД пропускают создание первичного ключа для таблицы либо потому, что не знают о его необходимости, либо ошибочно полагают, что PostgreSQL сам обеспечит его уникальность. Однако такое предположение может привести к серьезным проблемам, особенно по мере роста и усложнения вашей базы данных. Чтобы избежать подобных проблем, всегда назначайте первичный ключ для каждой таблицы.

Посмотрим несколько примеров предотвращения проблем с целостностью данных, возникающих из‑за отсутствия первичных ключей.

В примере запроса ниже мы при создании таблицы Orders указываем в качестве первичного ключа столбец order_id:

CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT NOT NULL,
order_date DATE NOT NULL
);

Иногда одного столбца недостаточно для однозначной идентификации строки. В таких случаях мы можем использовать составной ключ (комбинацию столбцов) в качестве первичного ключа. Например, в таблице order_items можно использовать и order_id, и product_id:

CREATE TABLE order_items (
order_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
PRIMARY KEY (order_id, product_id)
);

Если вы уже создали таблицу без первичного ключа, то вы все еще можете все исправить, просто добавив его с помощью команды ALTER TABLE. Например:

ALTER TABLE orders ADD PRIMARY KEY (order_id);

Как правило, отсутствие первичного ключа в таблице дает о себе знать достаточно быстро, однако некоторые другие ошибки, о которых речь пойдет дальше обнаружить бывает не так просто.

Чрезмерное усложнение схемы

Схема базы данных — это любая структура, которую вы определяете вокруг данных. Сюда входят представления, таблицы, отношения, поля, индексы, функции и другие элементы. Без них легко заблудиться в базе данных. Ниже пример достаточно простой схемы:

Но у большинства начинающих архитекторов БД возникает соблазн разработать схему базы данных с сотнями таблиц, сложными отношениями и ограничениями, чтобы гарантировать гибкость и масштабируемость. Такая практика часто приводит к переусложнению схемы, которую трудно поддерживать и в которой запросы будут потреблять значительный объем ресурсов.

При разработке схемы важно соблюдать баланс между нормализацией и простотой. Напомним, что нормализация базы данных — это процесс структурирования реляционной БД в соответствии с серией так называемых нормальных форм с целью сокращения избыточности данных и повышения их целостности.

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

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

Чем проще - тем лучше

Начните с минимальной схемы, которая отвечает вашим насущным потребностям. Избегайте добавления таблиц или столбцов, которые вам в данный момент не нужны. Например, если вы создаете таблицу пользователей, начните с основных полей, таких как id, имя и email:

CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
);

Нормализуйте вдумчиво. Нормализация важна, но не переусердствуйте. Например, разделение таблицы users на user_profiles, user_emails и user_addresses может показаться хорошей идеей, но это может привести к ненужной сложности. На рисунке ниже более простой правый вариант является более предпочтительным.

Вместо этого держите связанные данные вместе, если нет веских причин для их разделения.

Меньше внешних ключей

Избегайте чрезмерного использования внешних ключей. Хотя внешние ключи необходимы для поддержания связей между таблицами, их чрезмерное использование может усложнить вашу схему. В примере ниже столбец customer_id таблицы Sales является внешним ключом, связывающим ее с таблицей Customers.

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

Делать бэкап и УЖЕ делать бэкап

Потеря данных — это кошмарный сценарий, независимо от того, вызвана ли она вредоносной программой, человеческой ошибкой, наводнением или программным сбоем. Одна из распространенных ошибок, которую допускают большинство разработчиков, только начинающих работать с Postgres или базами данных, — это игнорирование важности резервного копирования, последствия которого могут быть катастрофическими.

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

Существуют различные способы резервного копирования данных. Можно сохранять БД в виде набора запросов, последовательное выполнение которых приведет к созданию точно такой же базы с такими же данными. А можно бэкапить файлы БД, в таком случае вам достаточно будет просто скопировать эти файлы в нужный каталог и подключить их к новой базе.

Самым распространенным инструментом бэкапа является утилита pg_dump. Она может создавать логические резервные копии (SQL‑скрипты) или физические резервные копии (бинарные копии файлов данных). Логические резервные копии обычно более гибкие, в то время как физические резервные копии быстрее восстанавливаются. Вот примеры ее использования:

pg_dump -U username -h hostname -p port database_name > backup.sql

pg_dump -U username -h hostname -p port -Fc database_name > backup.dump

В первом случае мы делаем логическую резервную копию, а во втором дамп в файл.

Также есть сторонние инструменты, такие как Barman или pgBackups, предоставляют расширенные возможности резервного копирования и восстановления для PostgreSQL. Эти инструменты упрощают управление резервным копированием и обеспечивают детализацию процесса резервного копирования.

Однако, важно не только своевременно делать резервные копии, но и регулярно проверять бекапы на возможность восстановления. Так при восстановлении из логического бэкапа есть вероятность, что какой‑либо запрос не выполнится корректно, в результате чего целостность базы будет нарушена.

При восстановлении из физической копии возможны проблемы, если версия новой СУБД будет чуть‑чуть не совпадать с версией базы, с которой делались бэкапы. Очень не хотелось бы столкнуться с подобными проблемами в случае реальной катастрофы.

Заключение

Сегодня мы рассмотрели несколько ошибок, которые могут допустить архитекторы, разработчики и администраторы баз данных, а также инженеры DevOps, работающие с СУБД. Отсутствие первичного ключа приведет к проблемам в работе базы довольно быстро, сложная схема может стать причиной проблем позднее. Но отсутствие рабочей резервной копии приведет к гораздо более серьезным последствиям в случае отказа БД. Поэтому важно не пренебрегать приведенными в статье рекомендациями.


Разработка схемы базы данных — это только начало. Настоящие вызовы начинаются, когда данные нужно надёжно развернуть, обновлять и не потерять. Чтобы сервисы действительно работали стабильно, масштабировались и обновлялись без боли, нужна следующая ступень — GitOps и DevOps-практики. Рекомендуем открытые уроки:

Теги:
Хабы:
-2
Комментарии12

Публикации

Информация

Сайт
otus.ru
Дата регистрации
Дата основания
Численность
101–200 человек
Местоположение
Россия
Представитель
OTUS