【发布时间】:2016-01-26 11:43:24
【问题描述】:
我正在使用SQLAlchemy 1.0.0,并且想要批量进行一些UPDATE ONLY(如果匹配主键则更新,否则不执行任何操作)查询。
我做了一些实验,发现批量更新看起来比批量插入或批量upsert慢得多。
您能否帮我指出为什么它运行如此缓慢,或者是否有任何替代方法/想法来制作BULK UPDATE (not BULK UPSERT) with SQLAlchemy?
下面是MYSQL中的表格:
CREATE TABLE `test` (
`id` int(11) unsigned NOT NULL,
`value` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
以及测试代码:
from sqlalchemy import create_engine, text
import time
driver = 'mysql'
host = 'host'
user = 'user'
password = 'password'
database = 'database'
url = "{}://{}:{}@{}/{}?charset=utf8".format(driver, user, password, host, database)
engine = create_engine(url)
engine.connect()
engine.execute('TRUNCATE TABLE test')
num_of_rows = 1000
rows = []
for i in xrange(0, num_of_rows):
rows.append({'id': i, 'value': i})
print '--------- test insert --------------'
sql = '''
INSERT INTO test (id, value)
VALUES (:id, :value)
'''
start = time.time()
engine.execute(text(sql), rows)
end = time.time()
print 'Cost {} seconds'.format(end - start)
print '--------- test upsert --------------'
for r in rows:
r['value'] = r['id'] + 1
sql = '''
INSERT INTO test (id, value)
VALUES (:id, :value)
ON DUPLICATE KEY UPDATE value = VALUES(value)
'''
start = time.time()
engine.execute(text(sql), rows)
end = time.time()
print 'Cost {} seconds'.format(end - start)
print '--------- test update --------------'
for r in rows:
r['value'] = r['id'] * 10
sql = '''
UPDATE test
SET value = :value
WHERE id = :id
'''
start = time.time()
engine.execute(text(sql), rows)
end = time.time()
print 'Cost {} seconds'.format(end - start)
num_of_rows = 100 时的输出:
--------- test insert --------------
Cost 0.568960905075 seconds
--------- test upsert --------------
Cost 0.569655895233 seconds
--------- test update --------------
Cost 20.0891299248 seconds
num_of_rows = 1000 时的输出:
--------- test insert --------------
Cost 0.807548999786 seconds
--------- test upsert --------------
Cost 0.584554195404 seconds
--------- test update --------------
Cost 206.199367046 seconds
到数据库服务器的网络延迟约为 500 毫秒。
看起来像批量更新它一个一个地发送和执行每个查询,而不是批量?
提前致谢。
【问题讨论】:
-
没有批量更新之类的东西。尝试将所有更新封装在一个事务中,看看效果如何。
-
@Shadow 还是很慢(花费几乎相同的时间),看起来它只是将每个更新查询一个一个发送到数据库,而每个发送操作的网络延迟是 500ms。
-
然后自己生成sql字符串,所有更新语句用;分隔并将其作为一个批次发送到您的数据库。
-
@Shadow 谢谢,它现在工作得更快了。但是 SQLAlchemy 实现批量插入/批量 upsert 的方式是否相同?之前我以为是先把SQL模板发送到数据库,然后再把这批数据发送到服务器,所以我想它也应该可以批量更新。
-
我再说一遍:没有批量更新这样的东西。有一个批量插入,但正如@pi 在他的回复中指出的那样,sqlalchemy 甚至不使用该语法。我不完全确定批量插入然后使用连接进行更新是否比使用单个事务批量发送更新语句要快得多。
标签: python mysql sqlalchemy bulkinsert bulkupdate