【发布时间】:2018-03-24 17:31:53
【问题描述】:
今天我花了一天的时间来改进我的 Python 脚本的性能,该脚本将数据推送到我的 Postgres 数据库中。我之前是这样插入记录的:
query = "INSERT INTO my_table (a,b,c ... ) VALUES (%s, %s, %s ...)";
for d in data:
cursor.execute(query, d)
然后我重新编写了我的脚本,以便它创建一个内存文件,而不是用于 Postgres 的 COPY 命令,这让我可以将数据从文件复制到我的表:
f = StringIO(my_tsv_string)
cursor.copy_expert("COPY my_table FROM STDIN WITH CSV DELIMITER AS E'\t' ENCODING 'utf-8' QUOTE E'\b' NULL ''", f)
COPY 方法快得惊人。
METHOD | TIME (secs) | # RECORDS
=======================================
COPY_FROM | 92.998 | 48339
INSERT | 1011.931 | 48377
但我找不到任何关于为什么的信息?它与多行 INSERT 的工作方式有何不同,从而使其速度更快?
# original
0.008857011795043945: query_builder_insert
0.0029380321502685547: copy_from_insert
# 10 records
0.00867605209350586: query_builder_insert
0.003248929977416992: copy_from_insert
# 10k records
0.041108131408691406: query_builder_insert
0.010066032409667969: copy_from_insert
# 1M records
3.464181900024414: query_builder_insert
0.47070908546447754: copy_from_insert
# 10M records
38.96936798095703: query_builder_insert
5.955034017562866: copy_from_insert
【问题讨论】:
-
什么是“更快”?请提供一些基准。
-
INSERT: 1011.93 seconds | COPY: 92.99 seconds。我的插入中有些东西使它比应有的速度慢,但是我见过的每个人都报告了巨大的改进。例如,请参见此处:gist.github.com/jsheedy/efa9a69926a754bebf0e9078fd085df6 -
对于每个 INSERT 语句,您都在执行隐式事务。我很好奇 COPY 是否以不同的方式处理它们。
-
复制是一个事务,单个插入没有开始;提交;将它们包装起来是单独的交易。复制一个错误的值会导致整个事情失败。对于单个自动提交的事务,一个值错误意味着一个值失败。您可以通过多行插入获得接近复制速度,例如插入表值 (a,b,c),(d,e,f),(g,h,i)...(x,y,z);
-
@Kyle 你确定吗?
psycopg2默认为非自动提交,在第一条语句上打开事务并保持打开状态直到显式提交。通常你是对的,但对于 Python 来说不一定。
标签: python postgresql sql-insert postgresql-copy