如何快速将约300GB /十亿条相关记录插入PostgreSQL数据库?

如何解决如何快速将约300GB /十亿条相关记录插入PostgreSQL数据库?

我已经为此工作了几个月,但仍然没有解决方案,希望我能从您那里得到帮助...

任务是,我需要将在线数据提供商的实时数据记录插入/导入到我们的数据库中。

实时数据以文件形式提供。每个文件包含多达200,000条json记录,一条记录一行。从2013年开始,每天都会在线提供数个/数十个文件。

我计算了整个文件存储,总大小约为300GB。我估计了记录的总数(我可以通过rest api来获取文件的大小,但不能获取每个文件的行号),它应该是10亿条左右或更多。

在将一条记录导入/插入数据库之前,我需要从记录中找出两个参数(站,参数)并建立关系。

因此工作流程类似于:

  1. 在数据库中查找参数,如果该参数存在于数据库中,则只需返回parameter.id;否则,应将参数作为新条目插入参数表中,并创建一个新parameter.id并返回;
  2. 类似地,在我们的数据库中查找该站点,如果该站点已经存在,则只需获取其id,否则将创建一个新站点并创建一个新station.id;
  3. 然后我可以将此json记录及其标识的parameter.id和station.id插入到我们的主数据表中,以建立关系。

基本上,它是一个简单的数据库结构,具有三个主表(数据,参数,站)。它们通过parameter.id和station.id相互关联,并具有主键/外键关系。

但是查询非常耗时,而且我找不到在可预见的时间内将大量数据正确插入数据库的方法。

我做了两次试验:

  1. 只需对批处理插入使用普通的SQL查询。 上面描述了工作流程。 对于每个记录a)获取parameter.id b)获取station.id c)插入该记录 即使批量插入,我一周也只能插入一百万条记录。记录并不短,包含大约20个字段。

  2. 之后,我尝试了以下操作: 我没有事先检查参数和桩号,只是使用COPY命令将记录复制到没有关系的中间表中。据我计算,所有十亿条记录都可以在十天内导入。 但是在COPY之后,我需要使用SQL查询select distinctgroup by手动找出所有明确的工作站(只有几个参数,所以我可以忽略参数部分),并在工作站表,然后UPDATE整个记录及其相应的station.id,但是此UPDATE操作花费的时间非常长。

这里是一个示例: 我花了半天的时间将33,000,000条记录导入到中间表中。 我查询了选择longitude,latitude from records group by longitude,latitude并得到4,500个电台 我将这4,500个电台插入电台表中 而且对于我的每个电台

update record set stationid = station.id where longitude=station.longitude and latitude=station.latitude

作业仍在运行,但我估计需要两天 这仅用于3000万条记录,我有10亿条。

所以我的问题是,如何才能将如此大量的数据快速插入数据库中?

非常感谢您!


2020-08-20 10:01 非常感谢大家的评论!

@Brits: 是的,不是,所有的“复制”都花费了24小时以上。一个“ COPY”命令用于一个json文件。对于每个文件,我需要执行以下操作:

  1. 下载文件
  2. 将Json文件(不进行站间关系检查,但使用参数检查将它简单,快捷,参数就像项目中的常量一样)平铺到CSV文本文件中以进行“ COPY”命令
  3. 通过Python执行“ COPY”命令 如果我在公司网络中大约需要1分钟,2和3,则大约需要一分钟才能处理包含约200,000条记录的Json文件;如果我在家工作,则大约需要20分钟。 因此,只需忽略“一个半天”语句。我的估计是,如果我在公司网络中工作,我将能够在10天之内将所有300GB /十亿条记录导入中间表而无需进行关系检查。

我认为我现在的问题不是将json内容移动到平面数据库表中,而是建立数据站之间的关系。 在平板中放置json内容后,我需要找出所有站点并使用以下命令更新所有记录:

  1. 从记录组中按经度,纬度选择经度,纬度和计数(*)
  2. 将这些经度纬度组合插入到台表中
  3. 对于站表中的每个条目,执行 更新记录集stationid = station.id,其中经度= station.longitude和纬度= station.latitude

上面的这3.需要很长时间(也只有1.3亿条记录需要花费几分钟,我不知道1.十亿条记录需要花费多长时间

@Mike Organek @Laurenz Albe非常感谢。现在,即使您的评论也让我难以理解。我将研究它们并给出反馈。


文件总数为100,000+ 我正在考虑首先解析所有文件并获得单个工作站,然后预先使用station.id和parameter.id进行“复制”。我将提供反馈。


2020-09-04 09:14

我终于得到了想要的东西,即使我不确定这是否正确。

自从我提出问题以来我做了什么:

  1. 解析所有json文件并按坐标提取唯一的电台并将其保存到电台表中
  2. 使用COPY命令再次解析所有json文件,并将所有字段保存到记录表中,参数ID来自常量,站ID来自1)

我在管道中进行了1)和2),它们是并行进行的。而且1)花费的时间比2)长,所以我总是需要让2)等待。

10天后,我将数据存储在postgres中,并带有ca。 15000个工作站,总计6.5亿条记录,每个记录都有对应的工作站ID。

@ steven-matison非常感谢,您能再解释一下吗?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-