我有一个经常性的工作,它从模板创建一个 Postgres (v11) 数据库并用数据加载它。数据的规模大约为 10 或 100 几百万行,因此出于性能原因,我在创建任何主键或索引之前批量插入数据。这是我目前的操作顺序:
- 创建表
- 批量
COPY
处理所有数据 - 创建主键
- 创建附加索引
创建主键和索引是此工作流程中最慢的部分。当通过 ANALYZE/VACUUM/REINDEX 重新计算统计数据会有帮助甚至是必要的时候,这个工作流程有什么意义吗?
我有一个经常性的工作,它从模板创建一个 Postgres (v11) 数据库并用数据加载它。数据的规模大约为 10 或 100 几百万行,因此出于性能原因,我在创建任何主键或索引之前批量插入数据。这是我目前的操作顺序:
COPY
处理所有数据创建主键和索引是此工作流程中最慢的部分。当通过 ANALYZE/VACUUM/REINDEX 重新计算统计数据会有帮助甚至是必要的时候,这个工作流程有什么意义吗?
假设我有这两个数据框(简化了我的问题):
+---------+
| user_id |
+---------+
| 1 |
| 2 |
| ... |
+---------+
+------------+------------+
| article_id | date |
+------------+------------+
| a | 2019-01-01 |
| b | 2018-03-03 |
| ... | |
+------------+------------+
还有一个用户-文章对的密集矩阵,其中每个值是我预测每个用户想要阅读每篇文章的程度(从 0 到 1):
+-----+------+------+-----+
| | 1 | 2 | ... |
+-----+------+------+-----+
| a | 0.54 | 0.99 | ... |
| b | 0 | 0.7 | ... |
| ... | ... | ... | ... |
+-----+------+------+-----+
我有一个网络应用程序需要做一些事情,比如返回给单个用户最推荐的 10 篇文章,或者给定日期范围内第 11 到 20 篇最推荐的文章等:
query: (user_id=123) AND (news_date IN ('2019-04-01', '2019-05-01')) LIMIT 10 OFFSET 10
+---------+-------+------+
| news_id | score | rank |
+---------+-------+------+
| g | 0.98 | 11 |
| d | 0.97 | 12 |
| ... | ... | ... |
| q | 0.8 | 20 |
+---------+-------+------+
挑战在于我的用户和文章数以万计,因此由于列限制,我不能将矩阵存储为 Postgres 表。
我可以将 Postgres 中的推荐分数存储在一个表中(user_id, article_id, score)
,这样查询起来会很快,但是这个表会有 100M+ 行并且更新成本很高,我每天都会这样做。
我目前的解决方案是将单个数据帧(news_id, news_date, user_1_score, user_2_score, ..., user_n_score)
作为 gzipped Parquet 文件存储在磁盘上,加载news_date
和user_x_score
列,然后过滤、排序和切片。唯一的缺点是我的网络主机有一个临时文件系统,所以这个文件需要在应用程序启动时下载。至少在 Web 请求期间获取数据的速度足够快。
我对列式数据存储了解不多,但我觉得其中一种产品可能对我的问题有好处。有人有想法吗?