我的MySQL表架构是:
CREATE DATABASE test_db;
USE test_db;
CREATE TABLE test_table (
id INT AUTO_INCREMENT,
last_modified DATETIME NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB;
当我运行以下基准脚本时,我得到:
b1:20.5559301376
b2:0.504406929016
from timeit import timeit
import MySQLdb
ids = range(1000)
query_1 = "update test_table set last_modified=UTC_TIMESTAMP() where id=%(id)s"
query_2 = "update test_table set last_modified=UTC_TIMESTAMP() where id in (%s)" % ", ".join(('%s', ) * len(ids))
db = MySQLdb.connect(host="localhost", user="some_user", passwd="some_pwd", db="test_db")
def b1():
curs = db.cursor()
curs.executemany(query_1, ids)
db.close()
def b2():
curs = db.cursor()
curs.execute(query_2, ids)
db.close()
print "b1: %s" % str(timeit(lambda:b1(), number=30))
print "b2: %s" % str(timeit(lambda:b2(), number=30))
为什么executemany
和IN
子句之间存在很大差异?
我使用的是Python 2.6.6和MySQL-python 1.2.3。
我能找到的唯一相关问题是 - Why is executemany slow in Python MySQLdb?,但它并不是我所追求的。
答案 0 :(得分:0)
executemany
反复来回MySQL服务器,然后MySQL服务器需要解析查询,执行查询并返回结果。这可能是在单个SQL语句中执行所有操作的速度的10倍,即使它更复杂。
但是,对于INSERT
,this表示它会做聪明的事情并为您构建多行INSERT
,从而提高效率。
因此,IN(1,2,3,...)
比UPDATE;UPDATE;UPDATE...
如果您有一系列ID,那么更好的是说WHERE id BETWEEN 1 and 1000
。这是因为它可以简单地扫描行而不是从头开始查找每一行。 (我假设id
被编入索引,可能是PRIMARY KEY
。)
此外,您可能正在运行使每个插入/更新/删除的设置成为自己的"事务"。这为每个UPDATE
增加了大量开销。在这种情况下,这可能是不可取的。我怀疑你希望整个1000行更新是原子的。
结论:仅对(a)executemany
或(b)必须单独运行的语句使用INSERTs
。