Вариант 3 самый быстрый
Если и когда вы сталкиваетесь с проблемами производительности, и если вы не можете решить их каким-либо другим способом, вариант № 3 - это путь.
Используйте триггеры для обновления
Вы должны использовать триггеры после вставки, обновления и удаления, чтобы поддерживать промежуточные итоги в таблице заказов в синхронизации с базовыми данными.
Будьте особенно осторожны при ретроспективном изменении цен и прочего, так как для этого потребуется полный пересчет всех промежуточных итогов.
Так что вам понадобится много триггеров, которые обычно не делают большую часть времени.
в случае изменения налоговой ставки в будущем она изменится для заказов, которых у вас еще нет
Если запуск триггера занимает много времени, убедитесь, что вы делаете эти обновления в непиковые часы.
Периодически запускать автоматическую проверку, чтобы убедиться в правильности кэшированных значений
Вы также можете сохранить подзапрос golden
, который вычисляет все значения и сравнивает их с сохраненными значениями в таблице заказов.
Выполняйте этот запрос каждую ночь, и он сообщит о любых отклонениях, чтобы вы могли видеть, когда денормализованные значения не синхронизированы.
Не выставлять счета-фактуры для заказов, которые не были обработаны запросом проверки
Добавьте дополнительное поле даты в таблицу order
с именем timeoflastsuccesfullvalidation
и установите для него значение null
, если проверка не удалась.
Только счета-фактуры с dateoflastsuccesfullvalidation
меньше, чем 24 часа назад.
Конечно, вам не нужно проверять полностью обработанные заказы, только ожидающие обработки заказы.
Вариант 1 может быть достаточно быстрым
Относительно # 1
Это также медленно.
Это во многом зависит от того, как вы запрашиваете БД.
Вы упоминаете подвыборы, в приведенном ниже основном законченном скелетном запросе я не вижу необходимости во многих подвыборах, поэтому вы меня немного озадачили.
SELECT field1,field2,field3
, oifield1,oifield2,oifield3
, NettItemCost * (1+taxrate) as TotalItemCost
, TotalShippingCost
, TotalHandlingCost
, NettItemCost * taxRate as TotalTaxCost
, (NettItemCost * (1+taxrate)) + TotalShippingCost + TotalHandlingCost as TotalCost
, TotalPaid
, somethingorother as TotalProfit
FROM (
SELECT o.field1,o.field2, o.field3
, oi.field1 as oifield1, i.field2 as oifield2 ,oi.field3 as oifield3
, SUM(c.productprice * oi.qty) as NettItemCost
, SUM(IFNULL(sc.shippingperkg,0) * oi.qty * p.WeightInKg) as TotalShippingCost
, SUM(IFNULL(hc.handlingperwhatever,0) * oi.qty) as TotalHandlingCost
, t.taxrate as TaxRate
, IFNULL(pay.amountpaid,0) as TotalPaid
FROM orders o
INNER JOIN orderitem oi ON (oi.order_id = o.id)
INNER JOIN products p ON (p.id = oi.product_id)
INNER JOIN prices c ON (c.product_id = p.id
AND o.orderdate BETWEEN c.validfrom AND c.validuntil)
INNER JOIN taxes t ON (p.tax_id = t.tax_id
AND o.orderdate BETWEEN t.validfrom AND t.validuntil)
LEFT JOIN shippingcosts sc ON (o.country = sc.country
AND o.orderdate BETWEEN sc.validfrom AND sc.validuntil)
LEFT JOIN handlingcost hc ON (hc.id = oi.handlingcost_id
AND o.orderdate BETWEEN hc.validfrom AND hc.validuntil)
LEFT JOIN (SELECT SUM(pay.payment) as amountpaid FROM payment pay
WHERE pay.order_id = o.id) paid ON (1=1)
WHERE o.id BETWEEN '1245' AND '1299'
GROUP BY o.id DESC, oi.id DESC ) AS sub
Подумав об этом, вам нужно будет разделить этот запрос на вещи, которые имеют отношение к заказу и заказу, но мне лень это делать сейчас.
Советы по скорости
Убедитесь, что у вас есть индексы для всех полей, включенных в критерии соединения.
Используйте таблицу MEMORY
для таблиц меньшего размера, например tax
и shippingcost
, и используйте индекс hash
для id
в таблицах памяти.