PostGres - 使用 execute 而不是 executemany 插入元组列表
PostGres - Insert list of tuples using execute instead of executemany
我正在插入数千行,时机和速度非常重要。我通过基准测试发现 postgres 可以使用 execute()
而不是 executemany()
更快地摄取我的行
这很适合我:
...
def insert(self, table, columns, values):
conn = self.connectionPool.getconn()
conn.autocommit = True
try:
with conn.cursor() as cursor:
query = (
f'INSERT INTO {table} ({columns}) '
f'VALUES {values} '
f'ON CONFLICT DO NOTHING;'
).replace('[', '').replace(']', '') # Notice the replace x2 to get rid of the list brackets
print(query)
cursor.execute(query)
finally:
cursor.close()
self.connectionPool.putconn(conn)
...
self.insert('types', 'name, created_at', rows)
在双 replace
之后,打印 query
returns 类似这样的内容并摄取行:
INSERT INTO types (name, created_at) VALUES ('TIMER', '2022-04-09 03:19:49'), ('Sequence1', '2022-04-09 03:19:49') ON CONFLICT DO NOTHING;
我的方法安全吗?是否有使用 execute
的更 pythonic 实现?
不,这不安全甚至不可靠 – Python repr
与 PostgreSQL 字符串语法不兼容(尝试一些带有单引号、换行符或反斜杠)。
考虑改为传递数组参数并使用 UNNEST
:
cursor.execute(
"INSERT INTO types (name, created_at)"
" SELECT name, created_at FROM UNNEST (%(names)s, %(created_ats)s) AS t",
{
'names': ['TIMER', 'Sequence1', ...],
'created_ats': ['2022-04-09 03:19:49', ...],
})
这是最好的解决方案,因为查询不依赖于参数(可以准备和缓存,统计信息可以很容易地分组,使得没有SQL注入漏洞很明显,可以很容易地记录没有数据的查询)。
否则,构建一个只在参数数量上是动态的查询,例如 VALUES ((%s, %s, ...), (%s, %s, ...), ...)
。请注意 PostgreSQL 有参数限制,因此您可能需要批量生产这些。
否则,使用psycopg2.sql.Literal
。
我正在插入数千行,时机和速度非常重要。我通过基准测试发现 postgres 可以使用 execute()
而不是 executemany()
这很适合我:
...
def insert(self, table, columns, values):
conn = self.connectionPool.getconn()
conn.autocommit = True
try:
with conn.cursor() as cursor:
query = (
f'INSERT INTO {table} ({columns}) '
f'VALUES {values} '
f'ON CONFLICT DO NOTHING;'
).replace('[', '').replace(']', '') # Notice the replace x2 to get rid of the list brackets
print(query)
cursor.execute(query)
finally:
cursor.close()
self.connectionPool.putconn(conn)
...
self.insert('types', 'name, created_at', rows)
在双 replace
之后,打印 query
returns 类似这样的内容并摄取行:
INSERT INTO types (name, created_at) VALUES ('TIMER', '2022-04-09 03:19:49'), ('Sequence1', '2022-04-09 03:19:49') ON CONFLICT DO NOTHING;
我的方法安全吗?是否有使用 execute
的更 pythonic 实现?
不,这不安全甚至不可靠 – Python repr
与 PostgreSQL 字符串语法不兼容(尝试一些带有单引号、换行符或反斜杠)。
考虑改为传递数组参数并使用
UNNEST
:cursor.execute( "INSERT INTO types (name, created_at)" " SELECT name, created_at FROM UNNEST (%(names)s, %(created_ats)s) AS t", { 'names': ['TIMER', 'Sequence1', ...], 'created_ats': ['2022-04-09 03:19:49', ...], })
这是最好的解决方案,因为查询不依赖于参数(可以准备和缓存,统计信息可以很容易地分组,使得没有SQL注入漏洞很明显,可以很容易地记录没有数据的查询)。
否则,构建一个只在参数数量上是动态的查询,例如
VALUES ((%s, %s, ...), (%s, %s, ...), ...)
。请注意 PostgreSQL 有参数限制,因此您可能需要批量生产这些。否则,使用
psycopg2.sql.Literal
。