Проектирование БД для расчета стоимости аудиоуслуги
При разработке цифрового сервиса по обработке аудио часто возникает задача гибкой тарификации. Цена зависит от длительности трека и выбранных пользователем дополнительных опций. В этой статье разбираем, как правильно спроектировать базу данных (БД) для такой логики, избегая избыточности через SKU.
Анализ бизнес-правил тарификации
Перед проектированием структуры БД четко определим условия расчета:
- Если длительность аудио меньше 60 секунд - стоимость равна 0 (бесплатно), независимо от выбранных опций.
- Если длительность 60 секунд и более - взимается плата за каждые полные или неполные 60 секунд (шаг тарификации).
- К базовой стоимости за минуту добавляется надбавка за каждую выбранную опцию, которая также рассчитывается поминутно.
Почему SKU не подходит?
SKU (Stock Keeping Unit) - это уникальный идентификатор товара с фиксированными характеристиками. В вашем случае количество комбинаций (длительность × набор опций) бесконечно, так как длительность - непрерывная величина. Создавать SKU для каждой секунды или минуты нецелесообразно и приведет к колоссальной избыточности данных.
Рекомендуемая структура БД
Оптимальное решение - хранить тарифные сетки и правила расчета, а итоговую цену вычислять динамически. Ниже пример логической схемы на SQL.
Таблица: services (услуги)
Хранит базовую информацию о типе обработки аудио.
CREATE TABLE services (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
base_price_per_minute DECIMAL(10,2) NOT NULL,
free_duration_seconds INT DEFAULT 60
);Таблица: options (опции)
Список дополнительных опций, влияющих на цену.
CREATE TABLE options (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
price_per_minute DECIMAL(10,2) NOT NULL
);Таблица: order_items (заказы)
Фиксирует конкретный заказ пользователя.
CREATE TABLE order_items (
id INT PRIMARY KEY AUTO_INCREMENT,
service_id INT NOT NULL,
duration_seconds INT NOT NULL,
FOREIGN KEY (service_id) REFERENCES services(id)
);Таблица: order_item_options (связь заказа с опциями)
CREATE TABLE order_item_options (
order_item_id INT NOT NULL,
option_id INT NOT NULL,
PRIMARY KEY (order_item_id, option_id),
FOREIGN KEY (order_item_id) REFERENCES order_items(id),
FOREIGN KEY (option_id) REFERENCES options(id)
);Логика расчета цены (на примере PHP или псевдокода)
// Получаем длительность в секундах
$durationSec = $orderItem->duration_seconds;
// Если меньше 60 секунд - бесплатно
if ($durationSec < 60) {
$totalPrice = 0;
} else {
// Округляем до минут вверх (ceil)
$minutes = ceil($durationSec / 60);
// Базовая стоимость
$totalPrice = $service->base_price_per_minute * $minutes;
// Добавляем стоимость опций
foreach ($options as $option) {
$totalPrice += $option->price_per_minute * $minutes;
}
}
echo $totalPrice;Альтернатива: хранение цены в кэше
Если производительность критична, можно кэшировать результат расчета для часто встречающихся комбинаций (например, длительность 120 сек + опции A,B). Но базовая структура БД остается без SKU.
Преимущества подхода
- Гибкость: легко добавлять новые опции и менять тарифы.
- Масштабируемость: не нужно генерировать миллионы SKU.
- Прозрачность: цена рассчитывается по четким правилам, легко аудируется.
Таким образом, для вашей задачи оптимально использовать реляционную БД с таблицами тарифов и опций, а не SKU. Это упростит поддержку и развитие сервиса.