我有一个脚本,通过自定义ORM生成数万个插入到postgres数据库中。你可以想象,它很慢。这用于开发目的,以便创建虚拟数据。我可以在Postgres级别进行简单的优化,以加快速度吗?它是唯一一个按顺序运行的脚本,并且不需要线程安全。
也许我可以关闭所有锁定,安全检查,触发器等?只是寻找一个快速而肮脏的解决方案,这将大大加快这一过程。
感谢。
答案 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的速度因子。