Проектирование БД для расчета стоимости аудиоуслуги

    При разработке цифрового сервиса по обработке аудио часто возникает задача гибкой тарификации. Цена зависит от длительности трека и выбранных пользователем дополнительных опций. В этой статье разбираем, как правильно спроектировать базу данных (БД) для такой логики, избегая избыточности через 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. Это упростит поддержку и развитие сервиса.

    Часто задаваемые вопросы