Postgres插入优化

时间:2010-12-03 18:14:44

标签: sql postgresql bulkinsert

我有一个脚本,通过自定义ORM生成数万个插入到postgres数据库中。你可以想象,它很慢。这用于开发目的,以便创建虚拟数据。我可以在Postgres级别进行简单的优化,以加快速度吗?它是唯一一个按顺序运行的脚本,并且不需要线程安全。

也许我可以关闭所有锁定,安全检查,触发器等?只是寻找一个快速而肮脏的解决方案,这将大大加快这一过程。

感谢。

7 个答案:

答案 0 :(得分:8)

插入数据的最快方法是COPY命令。 但这需要一个平面文件作为输入。我想生成平面文件不是一种选择。

不要经常提交,特别是在启用自动提交的情况下运行它。 “成千上万”听起来像最后一次提交就是正确的。

如果您可以设计您的ORM以利用Postgres的多行插入来加速事情的发展

这是多行插入的示例:

insert into my_table (col1, col2) 
values 
(row_1_col_value1, row_1_col_value_2), 
(row_2_col_value1, row_2_col_value_2), 
(row_3_col_value1, row_3_col_value_2)

如果您无法生成上述语法并且使用Java,请确保使用的是批处理语句而不是单个语句插入(可能其他DB层允许类似的内容)

编辑:

jmz'帖子激励我添加一些内容:

当您将wal_buffers增加到更大的值(例如8MB)和checkpoint_segments(例如16)时,您可能也会看到改进

答案 1 :(得分:8)

如果您在生产环境中不需要这种功能,我建议您从PostgreSQL配置中关闭fsync。这将大大加快插入速度。

永远不要关闭生产数据库上的fsync。

答案 2 :(得分:6)

对于数百到数千的插入,批处理:

begin;
insert1 ...
insert2 ...
...
insert10k ... 
commit;

对于数百万的插入使用副本:

COPY test (ts) FROM stdin;
2010-11-29 22:32:01.383741-07
2010-11-29 22:32:01.737722-07
... 1Million rows
\.

确保在另一个表中使用任何用作fk的col如果在另一个表中的大小超过平均值,则会被编入索引。

答案 3 :(得分:3)

您可以做的一件事是删除所有索引,执行插入操作,然后创建索引。

答案 4 :(得分:2)

您是否正在发送一批成千上万的INSERT 您要发送数以万计的INSERT吗?

我知道使用Hibernate,您可以批量处理所有SQL语句,并将它们最终发送到一个大块中,而不是单独制作成千上万个SQL语句的网络和数据库开销。

答案 5 :(得分:2)

如果您只是初始化常量测试数据,您还可以将测试数据放入临时表中,然后使用

复制表内容
INSERT INTO... SELECT...

应该和使用COPY一样快(尽管我没有对它进行基准测试),其优点是你可以只使用SQL命令进行复制,而无需设置像COPY那样的外部文件。

答案 6 :(得分:2)

尝试在一个请求中尽可能多地做!

insert into my_table (col1, col2) 
values (
  unnest(array[row_1_col_value_1, row_2_col_value_1, row3_col_value_1]), 
  unnest(array[row_1_col_value_2, row_2_col_value_2, row_3_col_value_2));

这类似于@a_horse_with_no_name的建议。使用unnest的优点是:您可以使用包含数组的查询参数!

insert into my_table (col1, col2) 
values (unnest(:col_values_1), unnest(:col_values_2));

通过将三个insert语句合并为一个,可以节省超过50%的执行时间。 通过在单个Insert中使用具有2000个值的查询参数,我在应用程序中获得了150的速度因子。