首页 > 解决方案 > 事务块会导致数据库上的 postgresql 中的错误提交或应用程序崩溃吗?

问题描述

我正在编写一个新模块,其中我全天每分钟从 kafka 轮询几千条记录,然后将它们分成两个表,然后提交给 kafka 代理。我打算对前一天收集的几百万条记录运行一些聚合查询

我将记录分成两个表,因为有效负载本质上是动态的,并且我只对 json 有效负载中的几个字段感兴趣。我的假设是,即使聚合必须仅在两列上运行,即使在运行查询时,整行也会加载到数据库的内存中。因此,只需从一开始就将负责计数的列提取到单独的表中。

Customer_Count我在哪里对每种购买类型的每种客户类型的计数运行聚合查询。

Customer_Payload我计划稍后将完整的有效负载归档到对象存储中。

我计划在一个事务块中进行批量插入,首先是有效负载表,然后是计数表,假设由于异常、应用程序或数据库崩溃导致在任一表中插入任何记录失败导致批量插入两者其中回滚。

由于我将每个事务的数千条记录写入两个表,因此在提交过程中数据库崩溃或应用程序崩溃是否有可能导致部分写入其中一个表

我的假设是,由于这是同步事务,因此在通过数据库级​​别提交之前的任何数据库崩溃都将被回滚。

对于事务不会提交的 Spring Boot 应用程序中的任何崩溃也是如此。

我格外谨慎,因为这些指标会导致下游的一些收入操作,因此存在关于部分提交可能性的问题。

桌子看起来有点像这样

计数表

create table customer_counts
(
id bigserial PK,
customer_id string Not Null,
count int,
purchase_type String,
process_dt date
) 
create index metric_counts_idx on (customer_id, purchase_type, process_dt)

有效载荷表

create table customer_payload
(
id bigserial PK,
customer_id string Not Null,
payload text,
process_dt date
) 
create index metric_payload_idx on (customer_id, process_dt)

然后我运行一个

select sum(count), customer_id, purchase_type 
from customer_counts 
group by customer_id, purchase_type

在一天结束时的计数表上有几百万条记录。

我只是使用有效负载表来选择并推送到对象存储。

PS:我还想知道是否在 customer_id、purchase_type、count 上创建索引可以让我免于为计数创建额外表的麻烦,但根据我的阅读,索引仅用于查找,并且聚合将在加载后运行整行。您不能保证查询计划者是否每次都考虑索引。关于这种方法的任何建议也将有助于将我的设计从两张表简化为一张表,将部分提交的问题限制为一张表。

我计划在 postgresql 中使用默认设置进行事务和提交。我们使用 Spring Boot JdbcTemplate 进行数据库访问和 @Transactionaljava 应用程序级别的块。有效负载的大小在 0.5 KB 到 10 KB 之间变化。我还索引了客户 ID、购买类型和日期。postgres 版本是 9.6。

标签: sqlpostgresqlspring-bootspring-mvctransactions

解决方案


您不会看到部分提交的事务。您的设置似乎没有什么令人担忧的。

“整行”的事情并不完全正确。PG实际上一次加载一个页面,这通常意味着> 1行 - 但一个页面将只包含相当紧凑的行数据,大值被压缩并带外存储(又名TOAST)。如果您既不选择也不过滤有效负载,则不应最终读取其大部分字段数据。

至于您的 PS,我认为这实际上应该适用于index-only scan。AIUI,你只会插入而不是更新/删除,这应该意味着绝大多数表对所有事务都是可见的,这是使仅索引扫描值得的重要因素。您可能希望在 customer_id、purchase_type 和 count 上使用单个索引,这可用于满足您的最终查询。


推荐阅读