Следует ли помещать вычисленные значения в базу данных?
В проекте я использую 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)