我正在编写一个新模块,在该模块中,我每天每分钟从kafka轮询几千条记录,然后将它们分成两个表,然后提交给kafka broker。我打算对前一天收集的几百万条记录进行一些汇总查询
我将记录分为两个表,因为有效负载本质上是动态的,并且我只对json有效负载中的几个字段感兴趣。我的假设是,即使在运行查询时,也会将整行加载到数据库的内存中,即使聚合只需在两列上运行。因此,只需从一开始就将负责计数的列提取到一个单独的表中。
Customer_Count在其中,我对每个客户类型和每个购买类型的计数运行聚合查询。
Customer_Payload其中,我计划稍后将全部负载归档到对象存储中。
我计划在一个事务块中进行批量插入,首先插入到有效负载表,然后插入到计数表,假设由于异常、应用程序或数据库崩溃而在其中一个表中插入任何记录失败,会导致对这两个表的批量插入回滚。
由于我正在将每个事务的几千条记录写入两个表,在进行提交时数据库崩溃或应用程序崩溃是否有可能导致部分写入其中一个表?
我的假设是,由于这是同步事务,所以在提交之前的任何数据库崩溃都将回滚到数据库级别的through。
对于春季启动应用程序中事务不会提交的任何崩溃也是如此。
我格外谨慎,因为这些指标会导致下游的一些收入运营,因此存在部分提交的可能性问题。
这些表格看起来有点像
计数表
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进行数据库访问,并在java应用程序级别使用@Transactional
块。有效载荷的大小在.5 KB到10 KB之间变化。我还对客户id、purchase_type和日期进行了索引。postgres版本是9.6。
您将不会看到部分提交的事务。你的设置似乎没有什么令人担忧的。
";整行";事情不太对劲。PG实际上一次加载一个页面,这通常意味着>1行-但一个页面只包含相当紧凑的行数据,大的值会被压缩并存储在带外(也称为TOAST(。如果您既不选择也不筛选有效负载,则不应该最终读取其大部分字段数据。
至于你的PS,我认为这实际上应该适用于仅索引扫描。AIUI,你只会插入,而不会更新/删除,这意味着表的绝大多数对所有事务都可见,这是使仅索引扫描值得的一个重要因素。你希望对customer_id、purchase_type和count使用一个索引,这可以用来满足你的最终查询。