Ответ
Да, я проектировал схемы как для реляционных (PostgreSQL, MySQL), так и для NoSQL (MongoDB, Redis) баз данных. Мой подход основан на балансе между производительностью, целостностью данных и гибкостью.
Ключевые принципы:
- Нормализация vs. Денормализация: Для реляционных БД я начинаю с нормализации (обычно до 3НФ), чтобы устранить избыточность данных и избежать аномалий. Однако, для высоконагруженных систем я применяю денормализацию в "горячих" местах для ускорения запросов на чтение (например, кэширование счетчиков или имен).
- Выбор типов данных: Правильный выбор типов данных (например,
INT
вместоVARCHAR
для ID,TIMESTAMP WITH TIME ZONE
для дат) критически важен для производительности, экономии места и корректности данных. - Индексация: Я тщательно подхожу к созданию индексов. Кроме первичных ключей, я добавляю индексы на внешние ключи (
foreign keys
) и на поля, которые часто используются вWHERE
,JOIN
иORDER BY
. Для сложных запросов использую составные (composite) индексы. - Связи и ограничения: Четко определяю связи (
1:1
,1:M
,M:M
) и использую ограничения (FOREIGN KEY
,UNIQUE
,NOT NULL
,CHECK
) для поддержания целостности данных на уровне самой БД.
Пример для PostgreSQL:
-- Таблица пользователей
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY, -- BIGSERIAL для больших таблиц
email VARCHAR(255) UNIQUE NOT NULL,
hashed_password TEXT NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW() -- TIMESTAMPTZ для работы с часовыми поясами
);
-- Таблица постов с внешним ключом и индексом
CREATE TABLE posts (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE, -- Каскадное удаление постов при удалении юзера
title TEXT NOT NULL,
content TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Индекс для быстрого поиска постов конкретного пользователя
CREATE INDEX idx_posts_user_id ON posts(user_id);
Для NoSQL (MongoDB):
Подход меняется. Вместо связей я часто использую встраивание (embedding) документов для атомарности операций и уменьшения количества запросов, если данные часто читаются вместе.
// Пример документа заказа, где информация о покупателе встроена
{
"_id": ObjectId("..."),
"order_date": ISODate("..."),
"total_price": 150.75,
"customer": { // Встроенный документ
"user_id": ObjectId("..."),
"name": "Alex",
"address": "123 Main St"
},
"items": [ /* ... */ ]
}