Psycopg2,Postgresql,Python:批量插入的最快方法

时间:2010-02-16 09:36:51

标签: python postgresql psycopg2

我正在寻找将数百万个元组批量插入数据库的最有效方法。我正在使用Python,PostgreSQL和psycopg2

我创建了一长串应该插入数据库的tulpes,有时使用几何Simplify等修饰符。

这种天真的方式是将INSERT语句列表字符串格式化,但我读过其他三种方法:

  1. 使用pyformat binding style进行参数化插入
  2. 在元组列表中使用executemany
  3. 使用将结果写入文件并使用COPY
  4. 似乎第一种方式效率最高,但我很感激您的见解和代码片段,告诉我如何正确地做到这一点。

9 个答案:

答案 0 :(得分:14)

是的,我会投票给COPY,前提是您可以将文件写入服务器的硬盘(而不是应用程序运行的驱动器),因为COPY只能读取服务器。

答案 1 :(得分:10)

有一个新的psycopg2 manual包含所有选项的示例。

COPY选项效率最高。然后是executemany。然后使用pyformat执行。

答案 2 :(得分:8)

根据我的经验executemany并不比自己运行多个插件快得多, 最快的方法是自己格式化具有多个值的单个INSERT,也许将来executemany会有所改善,但现在它很慢

我继承了list并重载了append方法,所以当列表达到一定大小时,我会格式化INSERT来运行它

答案 3 :(得分:6)

您可以使用a new upsert library

$ pip install upsert

(您可能必须先pip install decorator

conn = psycopg2.connect('dbname=mydatabase')
cur = conn.cursor()
upsert = Upsert(cur, 'mytable')
for (selector, setter) in myrecords:
    upsert.row(selector, setter)

其中selectordict对象,{'name': 'Chris Smith'}setterdict{ 'age': 28, 'state': 'WI' }

几乎与编写自定义INSERT [/ UPDATE]代码并直接使用psycopg2运行代码一样快......如果该行已经存在,它将不会爆炸。< / p>

答案 4 :(得分:1)

第一个和第二个将一起使用,而不是单独使用。第三个是服务器方面最有效的,因为服务器会所有努力工作。

答案 5 :(得分:1)

经过一些测试,unnest通常似乎是一个非常快的选择,因为我从 @Clodoaldo Neto answer中学到了类似的问题。

data = [(1, 100), (2, 200), ...]  # list of tuples

cur.execute("""CREATE TABLE table1 AS
               SELECT u.id, u.var1
               FROM unnest(%s) u(id INT, var1 INT)""", (data,))

但是,can be tricky with extremely large data

答案 6 :(得分:1)

使用SQLalchemy的任何人都可以尝试1.2版本,当使用use_batch_mode = True初始化引擎时,添加了对批量插入的支持以使用psycopg2.extras.execute_batch()而不是executemany:

engine = create_engine(
    "postgresql+psycopg2://scott:tiger@host/dbname",
    use_batch_mode=True)

http://docs.sqlalchemy.org/en/latest/changelog/migration_12.html#change-4109

然后有人必须使用SQLalchmey不会费心去尝试sqla和psycopg2的不同组合并将SQL直接组合在一起。

答案 7 :(得分:0)

一个非常相关的问题:Bulk insert with SQLAlchemy ORM

所有道路通往罗马,但其中一些穿越山脉,需要渡轮,但如果您想快速到达那里,只需走高速公路。

在这种情况下,高速公路将使用execute_batch()psycopg2功能。文档说它是最好的:

executemany()的当前实施(使用非常慈善的轻描淡写)并不是特别有效。这些函数可用于加速针对一组参数重复执行语句。通过减少服务器往返次数,性能可以比使用executemany()好几个数量级。

在我自己的测试中execute_batch() 大约是executemany()的两倍,并提供了配置page_size以进一步调整的选项(如果你想挤压最后一个)驱动程序性能的2-3%。)

使用use_batch_mode=True

实例化引擎时,通过将create_engine()设置为参数来使用SQLAlchemy,可以轻松启用相同的功能

答案 8 :(得分:0)

插入许多项目的最新方法是使用 execute_values 助手 (https://www.psycopg.org/docs/extras.html#fast-execution-helpers)。

from psycopg2.extras import execute_values

insert_sql = "INSERT INTO table (id, name, created) VALUES %s"
# this is optional
value_template="(%s, %s, to_timestamp(%s))"

cur = conn.cursor()

items = []
items.append((1, "name", 123123))
# append more...

execute_values(cur, insert_sql, items, value_template)
conn.commit()