Денормализация — это преднамеренное нарушение нормальных форм базы данных с целью повышения производительности за счет избыточного хранения данных. В отличие от нормализации, которая минимизирует дублирование, денормализация сознательно допускает дублирование для оптимизации операций чтения.
Частые сложные JOIN-операции:
Аналитические системы (OLAP):
Высоконагруженные read-heavy системы:
-- Нормализованная структура
CREATE TABLE Orders (
Id INT PRIMARY KEY,
CustomerId INT,
OrderDate DATE
);
CREATE TABLE OrderItems (
Id INT PRIMARY KEY,
OrderId INT,
ProductId INT,
Quantity INT,
Price DECIMAL
);
-- Денормализованный вариант
ALTER TABLE Orders ADD TotalAmount DECIMAL;
-- Нормализованная структура
CREATE TABLE Products (
Id INT PRIMARY KEY,
Name VARCHAR(100),
CategoryId INT
);
CREATE TABLE Categories (
Id INT PRIMARY KEY,
Name VARCHAR(50)
);
-- Денормализованный вариант
ALTER TABLE Products ADD CategoryName VARCHAR(50);
-- Вместо отдельных таблиц Users и UserProfiles
CREATE TABLE DenormalizedUsers (
UserId INT PRIMARY KEY,
Username VARCHAR(50),
Email VARCHAR(100),
FirstName VARCHAR(50),
LastName VARCHAR(50),
Address TEXT
);
Увеличение скорости чтения:
Упрощение запросов:
// Денормализованный запрос проще
var orders = db.Orders
.Where(o => o.TotalAmount > 1000)
.ToList();
// Нормализованный требует соединения
var orders = db.Orders
.Join(db.OrderItems,
o => o.Id,
oi => oi.OrderId,
(o, oi) => new { Order = o, Item = oi })
.GroupBy(x => x.Order)
.Where(g => g.Sum(i => i.Item.Price * i.Item.Quantity) > 1000)
.Select(g => g.Key)
.ToList();
Уменьшение нагрузки на сервер:
Аномалии данных:
Усложнение операций записи:
// При денормализации нужно обновлять несколько мест
void UpdateProductPrice(int productId, decimal newPrice)
{
// Обновляем основную таблицу
db.Products.Where(p => p.Id == productId)
.Set(p => p.Price, newPrice)
.Update();
// И денормализованные копии
db.OrderItems.Where(oi => oi.ProductId == productId)
.Set(oi => oi.Price, newPrice)
.Update();
}
Увеличение размера базы данных:
Материализованные представления:
CREATE MATERIALIZED VIEW CustomerOrdersSummary AS
SELECT c.Id, c.Name, COUNT(o.Id) as OrderCount, SUM(o.Total) as TotalSpent
FROM Customers c
JOIN Orders o ON c.Id = o.CustomerId
GROUP BY c.Id, c.Name;
CQRS (Command Query Responsibility Segregation):
Триггеры для поддержания согласованности:
CREATE TRIGGER UpdateOrderTotal
AFTER INSERT OR UPDATE OR DELETE ON OrderItems
FOR EACH ROW
EXECUTE PROCEDURE RecalculateOrderTotal();
денормализация — это мощный инструмент оптимизации производительности, который следует применять осознанно. Она особенно эффективна в read-heavy сценариях, но требует тщательного проектирования механизмов поддержания согласованности данных.