Следует ли помещать вычисленные значения в базу данных?

В проекте я использую django, django-rest-framework, базу данных postgresql + react/next на frontend. В процессе разработки приложения я столкнулся с проблемой, которую, за неимением большего опыта, не могу решить самостоятельно, несмотря на прочтение десятков похожих тем. В каждой теме проявляется одно утверждение: it depends.

Хранить вычисленные итоги в базе данных или вычислять их при каждом запросе?

Приложение представляет собой простейшую WMS (прием товара, заказы, отпуск товара, счета и т.д.) с возможностью отображения отчетов с графиками. Проблема, однако, заключается в объеме итоговых данных, с которыми я никогда не сталкивался.

1000 заказов в день * 40 продуктов на заказ * 25 рабочих дней * 12 месяцев = 12 000 000 строк

и из этих данных будут сделаны расчеты, например, графики о прибыли, общей выручке, сумме налога и т.д.

Документы не будут меняться практически никогда, итоговые значения тоже. Однако, я буду читать эти значения довольно часто, будь то в панели клиента о счетах, заказах или charts..... Боюсь, что пересчитывать эти значения каждый раз будет плохим решением. С другой стороны, эти значения используются для последующих вычислений довольно много ~20/30, может больше.

Для отображения данных в datagrid я, конечно, буду использовать пагинацию, поэтому размер данных не должен вызывать проблем даже при вычислении значений. Однако как насчет подготовки данных для построения графика. Давайте проверим прибыль по позиции в течение года. Вместо того чтобы упрощенно отфильтровать pzitems для данного товара и сложить поле прибыли, вам придется отфильтровать pzitems для данного товара и вычесть из каждой позиции цену покупки - цену продажи * скидку. Будет ли это работать быстро или лучше нарушить нормализацию базы данных и использовать более простой расчет.

Ниже приведен пример модели (значения сделаны на лету)

class DocumentProductInformation(models.Model):
    product = models.ForeignKey("catalogues.Product", on_delete=models.CASCADE)
    quantity = models.IntegerField(default = 0)

    price = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
    total = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
    final_price = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
    final_total = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)

    gross_price = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
    gross_total = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
    gross_final_price = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
    gross_final_total = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)

    discount = models.DecimalField(max_digits=4, decimal_places=2, default=0.00, validators=[MinValueValidator(0), MaxValueValidator(1)])

    markup = models.DecimalField(max_digits=6, decimal_places=2, default=0.00)
    margin = models.DecimalField(max_digits=4, decimal_places=2, default=0.00)
    
    sales_tax_rate = models.ForeignKey("catalogues.TaxRate", related_name='%(class)s_sales_tax_rate', on_delete=models.CASCADE, blank=True, null=True)
    purchase_tax_rate = models.ForeignKey("catalogues.TaxRate", related_name='%(class)s_purchase_tax_rate', on_delete=models.CASCADE, blank=True, null=True)

    sales_price = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
    sales_total = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
    sales_final_price = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
    sales_final_total = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)

    sales_gross_price = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
    sales_gross_total = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
    sales_gross_final_price = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
    sales_gross_final_total = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)

    profit = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)

Все, что указано выше, может быть вычислено из этих полей ниже:

    product = models.ForeignKey("catalogues.Product", on_delete=models.CASCADE)
    quantity = models.IntegerField(default = 0)
    price = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
    price = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
    discount = models.DecimalField(max_digits=4, decimal_places=2, default=0.00, validators=[MinValueValidator(0), MaxValueValidator(1)])
    markup = models.DecimalField(max_digits=6, decimal_places=2, default=0.00)
    margin = models.DecimalField(max_digits=4, decimal_places=2, default=0.00)
    sales_price = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
Вернуться на верх