对Postgres进行批量插入最快的方法是什么?
我需要以编程方式插入数十万的logging到Postgre数据库。 目前我在单个“查询”中执行1000个插入语句。
有没有更好的方法来做到这一点,我不知道一些大容量插入语句?
PostgreSQL有一个关于如何最好地填充数据库的指南 ,他们build议使用COPY命令来批量加载行。 本指南还介绍了如何加快进程的一些其他好的提示,例如在加载数据之前删除索引和外键(以及之后添加它们)。
有一个使用COPY的替代方法,这是Postgres支持的多行值语法。 从文档 :
INSERT INTO films (code, title, did, date_prod, kind) VALUES ('B6717', 'Tampopo', 110, '1985-02-10', 'Comedy'), ('HG120', 'The Dinner Game', 140, DEFAULT, 'Comedy');
上面的代码插入了两行,但是你可以任意扩展它,直到你达到最大数量的准备语句标记(可能是999美元,但我不是100%确定的)。 有时候不能使用COPY,这是对这些情况的有效替代。
一种加快速度的方法是在一个事务中明确地执行多个插入或复制(比如1000)。 Postgres的默认行为是在每个语句后提交,所以通过批量提交,可以避免一些开销。 正如丹尼尔答案中的指导所说,你可能必须禁用自动提交才能使其工作。 还要注意底部的意见,build议将wal_buffers的大小增加到16 MB也可能有所帮助。
它主要依赖于数据库中的(其他)活动。 像这样的操作有效地冻结了整个数据库的其他会话。 另一个考虑因素是数据模型和约束,触发器等的存在
我的第一个方法是:创build一个类似于目标表的结构(temp)表(创build表tmp AS select * from target where 1 = 0),然后将文件读入temp表。 然后我检查可以检查的内容:重复项,已经存在于目标中的键等
然后,我只是做一个“插入目标select *从tmp”或类似的。
如果这个失败,或者需要太长时间,我会放弃它,并考虑其他方法(暂时丢弃索引/约束等)
您可以使用COPY table TO ... WITH BINARY
,它“ 比文本和CSV格式稍快 ”。 只有在有数百万行插入的情况下才能做到这一点,而且如果您对二进制数据感到满意的话。
这是Python中的一个例子,使用psycopg2和二进制input 。
数组的UNNEST
函数可以和多行VALUES语法一起使用。 我认为这个方法比使用COPY
要慢,但是在使用psycopg和python(传递给cursor.execute
python list
变成pg ARRAY
)时对我有用:
INSERT INTO tablename (fieldname1, fieldname2, fieldname3) VALUES ( UNNEST(ARRAY[1, 2, 3]), UNNEST(ARRAY[100, 200, 300]), UNNEST(ARRAY['a', 'b', 'c']) );
没有VALUES
使用子select与额外的存在检查:
INSERT INTO tablename (fieldname1, fieldname2, fieldname3) SELECT * FROM ( SELECT UNNEST(ARRAY[1, 2, 3]), UNNEST(ARRAY[100, 200, 300]), UNNEST(ARRAY['a', 'b', 'c']) ) AS temptable WHERE NOT EXISTS ( SELECT 1 FROM tablename tt WHERE tt.fieldname1=temptable.fieldname1 );
批量更新的语法相同:
UPDATE tablename SET fieldname1=temptable.data FROM ( SELECT UNNEST(ARRAY[1,2]) AS id, UNNEST(ARRAY['a', 'b']) AS data ) AS temptable WHERE tablename.id=temptable.id;
我用原生libpq方法实现了非常快速的Postgresq数据加载器。 试试我的软件包https://www.nuget.org/packages/NpgsqlBulkCopy/
我刚刚遇到这个问题,并会推荐csvsql批量导入到Postgres。 要执行批量插入,只需创buildcsvsql
,然后使用连接到数据库的csvsql
,并为整个CSV文件夹创build单个表。
$ createdb test $ csvsql --db postgresql:///test --insert examples/*.csv