批量插入数亿条记录

时间:2010-05-16 02:27:52

标签: postgresql bulkinsert

将237万条记录插入到具有规则的表中(用于跨子表分发数据)的最快方法是什么?

我已经尝试或考虑过:

  1. 插入陈述。
  2. 交易插入(BEGINCOMMIT)。
  3. COPY FROM命令。
  4. http://pgbulkload.projects.postgresql.org/
  5. 插入太慢(四天)而COPY FROM忽略规则(还有其他问题)。

    示例数据:

    station_id,taken,amount,category_id,flag
    1,'1984-07-1',0,4,
    1,'1984-07-2',0,4,
    1,'1984-07-3',0,4,
    1,'1984-07-4',0,4,T
    

    表格结构(包含一条规则):

    CREATE TABLE climate.measurement
    (
      id bigserial NOT NULL,
      station_id integer NOT NULL,
      taken date NOT NULL,
      amount numeric(8,2) NOT NULL,
      category_id smallint NOT NULL,
      flag character varying(1) NOT NULL DEFAULT ' '::character varying
    )
    WITH (
      OIDS=FALSE
    );
    ALTER TABLE climate.measurement OWNER TO postgres;
    
    CREATE OR REPLACE RULE i_measurement_01_001 AS
        ON INSERT TO climate.measurement
       WHERE date_part('month'::text, new.taken)::integer = 1 AND new.category_id = 1 DO INSTEAD  INSERT INTO climate.measurement_01_001 (id, station_id, taken, amount, category_id, flag)
      VALUES (new.id, new.station_id, new.taken, new.amount, new.category_id, new.flag);
    

    数据最初是在MySQL中,但出于性能原因必须切换到PostgreSQL(并利用PL / R扩展)。

    谢谢!

3 个答案:

答案 0 :(得分:10)

将输入拆分为数据库外的单独文件,并使用COPY上传每个文件,而不是依赖规则来分发它们。如果你给出的规则是任何一个例子,那就是要应用的简单文本转换。此外,如果您的磁盘系统达到最佳状态,前面拆分将允许您并行加载拆分文件。

说真的,不要依赖规则来为批量加载执行此分发。实际上总是这样的情况是,批量加载和事务加载需要不同的方法,除非你准备强制一个或另一个(通常,等待)。

例如,您的规则使用date_part()从日期中提取月份 - 因此,为了确定子表,postgres需要分析日期字符串,将其转换为时间戳,然后将时间戳转换回日历只是为了让月份字段再次退出。但是,如果你正在写一些事情要事先做到这一点,你可以做substr($date,5,2)(或等效的):你认为哪个会更快?

这也是一个清理数据格式的机会,因此COPY会接受它。请注意,您可以使用COPY命令指定列:如果您没有使用该架构和示例文件执行该操作,则由于前面的额外“id”列而导致错误。 (“从csv标题中复制”可能已经计算出来了,但也许不是......“标题”选项可能只是让它跳过第一行)。

我在几小时内自己将大约280e6行加载到postgresql实例中,所以这肯定不是不可能的。对于这个初始加载,我已经关闭了fsync = off;计划是加载积压,然后再次将其重新打开以进行常规日常装载。我必须设置checkpoint_segments = 40以避免在日志中收到检查点警告。这只是加载到我的开发机器上 - 我正在使用专用磁盘用于数据库,这与用于xlogs的磁盘不同(即我在大磁盘上创建了一个表空间并在该表空间内创建了数据库)。实例的shared_buffers设置为1Gb,checkpoint_target设置为0.5。我尝试并行加载一些分区并没有提供太多改进,所以我怀疑慢速磁盘是瓶颈而不是数据库本身。

还有另外1.7e9行......明天应该在我希望的时候完成。

答案 1 :(得分:3)

  1. 创建没有任何索引的父表,只有列和那些类型(创建表some_data(c_1 int,c_2 varchar,....))
  2. 为新数据表枚举创建序列
  3. 从序列中获取新ID
  4. 使用'like'关键字为实际数据创建新表(创建表some_data_X,如some_data)
  5. 在some_data_X中插入实际数据,并以二进制格式复制
  6. 创建索引,时间限制等(使用多个连接到postgresql来强化你的核心)
  7. 继承父表
  8. 现在准备选择了! 通过这种方式,我可以在10列(2 xeon,24核,24 Gb内存,SSD)上创建索引,每秒实现400000-500000次插入。
  9. 奖励:在separete线程中删除旧数据(some_data_X with min X):带索引的巨大循环缓冲区!

答案 2 :(得分:0)

PostgreSQL文档包含populating a database上的页面,一旦您按照araqnid的建议预处理输入就可以帮助您,这样您就可以使用COPY

相关问题