我们正在实现一个电子商务数据模型,并努力在Postgres生成的列,Hasura计算字段和Postgres视图之间做出选择。
为了简化起见,我们有两个表:
items
------------
id
order_id
unit_price
quantity
orders
------------
id
我们现在要向items
表(unit_price * quantity
(添加total_price
,并将total_price
添加到订单(订单中所有items
total_price
的sum
(。
在第一种情况下,我们使用了 Postgres 生成的列。这里的好处似乎是它生成一次并存储,而不是像 Hasura 计算字段那样在每个查询上重新运行。
这是正确的选择吗?
items
------------
id
order_id
unit_price
quantity
total_price : Postgres generated column : (unit_price * quantity)
CREATE TABLE orders (
...,
total_price integer GENERATED ALWAYS AS (unit_price * quantity) STORED
);
在第二种情况下,我们不能使用生成的列,因为它不能引用其他表中的字段。
相反,我们可以使用 Hasura 计算字段来解决这个问题:
orders
------------
id
total_price : Hasura computed field : SUM(items.total_price)
CREATE FUNCTION calculate_order_total_price(orders_row orders)
RETURNS INTEGER AS $$
SELECT CAST(SUM(total_price) AS INTEGER)
FROM items
WHERE order_id = orders_row.id
$$ LANGUAGE sql STABLE;
或者,我们可以创建一个 Postgres 视图:
vw_orders
------------
orders.id
total_price : SELECT SUM(items.total_price)
CREATE VIEW vw_orders AS
SELECT orders.id,
(SELECT sum(items.total_price) AS sum
FROM items
WHERE (items.order_id = orders.id)) AS total_price
FROM orders;
Hasura 计算字段解决方案的缺点是total_price
仅在 GraphQL 查询中公开,因此我们无法在 SQL 中使用它。
乍一看,Postgres视图解决方案似乎没有任何问题。
我们错过了什么吗?
为什么人们会使用 Hasura 计算字段而不是 Postgres 生成的字段或视图?
是否有比较表或流程图可以帮助我们确定哪种方法最适合每种特定情况?
最后,对于所有这些,我们当然也可以使用 Postgres 触发器、Hasura 事件触发器和 Hasura 操作......这些什么时候是合适的解决方案?
干杯!
对于这种特定情况,我会使用 PostgreSQL 视图,因为所涉及的计算非常便宜(单次乘法(。甚至可能是存储空间的节省和顺序扫描中由此产生的速度提升超过了在需要值时必须执行计算的缺点。最近的PostgreSQL版本也可以使用实时编译(JIT(来使此类表达式的计算成本更低(对于更大的查询(。
一般来说,最佳策略可能取决于表达式的计算强度。如果该值很高,并且行的读取频率高于写入频率,则使用生成的列可能是有意义的。
您可以运行一个小基准测试并检查差异。在您的情况下,我认为影响不会很大,最好选择最简单或最具可读性的实现,因为这可以提高可维护性。