如何避免使用python的MySQLdb进行多次查询?

如何避免使用python的MySQLdb进行多次查询?,python,mysql-python,Python,Mysql Python,我正在读取一些原始文件并将它们插入数据库。这将涉及数百万条记录,对于每条记录,我有多个插入(许多表)。当我在本地测试时,它运行得很快,但是对于整个数据集,我需要使用远程数据库。这种方式速度非常慢,我想这是因为网络上的所有删除/插入操作 我正在使用MySQLdb模块(python),目前,我有如下内容: # setup connection con = mdb.connect('remote.host', 'database_user', '123456789', 'database_name')

我正在读取一些原始文件并将它们插入数据库。这将涉及数百万条记录,对于每条记录,我有多个插入(许多表)。当我在本地测试时,它运行得很快,但是对于整个数据集,我需要使用远程数据库。这种方式速度非常慢,我想这是因为网络上的所有删除/插入操作

我正在使用MySQLdb模块(python),目前,我有如下内容:

# setup connection
con = mdb.connect('remote.host', 'database_user', '123456789', 'database_name');

... read files, loop through records, etc...

# clear out data related to current record
cur.execute("DELETE FROM articles WHERE article_id = %s", article.id)
cur.execute("DELETE FROM authors WHERE article_id = %s", article.id)
cur.execute("DELETE FROM addresses WHERE article_id = %s", article.id)
cur.execute("DELETE FROM citation_references WHERE article_id = %s", article.id)
cur.execute("DELETE FROM citation_patents WHERE article_id = %s", article.id)

# insert the article
cur.execute("INSERT INTO articles (article_id, doctype, keywords, language, title) VALUES (%s, %s, %s, %s, %s, %s)" , (article.id, article.doctype, ';'.join(article.keywords), article.language, article.title))

# insert all the authors
for au in article.authors:
    cur.execute("INSERT INTO isi_authors (article_id, name_first, name_last, email) VALUES (%s, %s, %s, %s)", (article.id, au.first_name, au.last_name, au.email))

... other loops like the authors to insert 10-20 citations per article, multiple addresses, etc ...

据我所知,MySQLdb不允许我一次发送多个查询。我一定有办法避免网络延迟。有什么想法吗?

使用
executemany
。以下是来自以下方面的示例:

在您的情况下,它看起来像这样:

sql = "INSERT INTO isi_authors (article_id, name_first, name_last, email) VALUES (%s, %s, %s, %s)"
params = [(article.id, au.first_name, au.last_name, au.email) for au in article.authors]
cur.executemany(sql, params)
MYSQL_OPTION_MULTI_STATEMENTS_ON = 0
MYSQL_OPTION_MULTI_STATEMENTS_OFF = 1

conn.set_server_option(MYSQL_OPTION_MULTI_STATEMENTS_ON)
# Multiple statement execution here...
conn.set_server_option(MYSQL_OPTION_MULTI_STATEMENTS_OFF)
executemany
的文档中:

此方法提高了多行插入和插入的性能 代替否则,它相当于使用 执行()


使用
executemany
。以下是来自以下方面的示例:

在您的情况下,它看起来像这样:

sql = "INSERT INTO isi_authors (article_id, name_first, name_last, email) VALUES (%s, %s, %s, %s)"
params = [(article.id, au.first_name, au.last_name, au.email) for au in article.authors]
cur.executemany(sql, params)
MYSQL_OPTION_MULTI_STATEMENTS_ON = 0
MYSQL_OPTION_MULTI_STATEMENTS_OFF = 1

conn.set_server_option(MYSQL_OPTION_MULTI_STATEMENTS_ON)
# Multiple statement execution here...
conn.set_server_option(MYSQL_OPTION_MULTI_STATEMENTS_OFF)
executemany
的文档中:

此方法提高了多行插入和插入的性能 代替否则,它相当于使用 执行()


mySQL插入语法确实允许这样做。比较1)和2)

在第二种情况下,一次插入三行

希望它能给你一些想法


PS:这是一种独立于语言的方式,mySQL插入语法允许它。比较1)和2)

在第二种情况下,一次插入三行

希望它能给你一些想法


PS:这是一种独立于语言的方式,至少
MySQLdb
1.2.3似乎允许进行多个开箱即用的查询,您只需调用
cursor.nextset()
来循环返回的结果集

db = conn.cursor()
db.execute('SELECT 1; SELECT 2;')

more = True
while more:
    print db.fetchall()
    more = db.nextset()
如果您想绝对确保对此的支持已启用,和/或禁用该支持,可以使用以下方法:

sql = "INSERT INTO isi_authors (article_id, name_first, name_last, email) VALUES (%s, %s, %s, %s)"
params = [(article.id, au.first_name, au.last_name, au.email) for au in article.authors]
cur.executemany(sql, params)
MYSQL_OPTION_MULTI_STATEMENTS_ON = 0
MYSQL_OPTION_MULTI_STATEMENTS_OFF = 1

conn.set_server_option(MYSQL_OPTION_MULTI_STATEMENTS_ON)
# Multiple statement execution here...
conn.set_server_option(MYSQL_OPTION_MULTI_STATEMENTS_OFF)

如果在执行其中一个查询时出错,mysql将不会在该点之后执行任何查询。如果异常源于第一次查询,则调用
db.execute()
将抛出异常,否则相应的
db.nextset()
将抛出异常,因此您可以在获取异常之前从成功的查询中获取结果集。

至少
MySQLdb
1.2.3似乎允许开箱即用的多个查询,您只需调用
cursor.nextset()
即可遍历返回的结果集

db = conn.cursor()
db.execute('SELECT 1; SELECT 2;')

more = True
while more:
    print db.fetchall()
    more = db.nextset()
如果您想绝对确保对此的支持已启用,和/或禁用该支持,可以使用以下方法:

sql = "INSERT INTO isi_authors (article_id, name_first, name_last, email) VALUES (%s, %s, %s, %s)"
params = [(article.id, au.first_name, au.last_name, au.email) for au in article.authors]
cur.executemany(sql, params)
MYSQL_OPTION_MULTI_STATEMENTS_ON = 0
MYSQL_OPTION_MULTI_STATEMENTS_OFF = 1

conn.set_server_option(MYSQL_OPTION_MULTI_STATEMENTS_ON)
# Multiple statement execution here...
conn.set_server_option(MYSQL_OPTION_MULTI_STATEMENTS_OFF)

如果在执行其中一个查询时出错,mysql将不会在该点之后执行任何查询。如果异常源于第一个查询,则
db.execute()
调用将抛出异常,否则相应的
db.nextset()
将抛出异常,因此,您可以在获取异常之前从成功的查询中获取结果集。

看起来简单地正确使用外键关系并级联删除将解决您的一些问题。看起来简单地正确使用外键关系并级联删除将解决您的一些问题。我在impression ExecuteMy仍然做了多次轮滑。我错了吗?@pocketfullofcheese:根据代码文档,它“提高了多行插入和替换的性能”。看我的更新。太好了。谢谢我完全错过了。对于多次删除,您有什么建议?按照内噬菌体在原始帖子评论中的建议设置级联?@pocketfullofcheese:有时候级联删除是有意义的,在这种情况下,使用它们可以提高性能。但有时您可能不希望通过级联删除来避免意外的数据丢失,在这种情况下,您应该坚持当前的方法。我想大部分时间都是因为插入循环效率低下,而不是因为删除。我当时的印象是,executemany仍在执行多个roudtrips。我错了吗?@pocketfullofcheese:根据代码文档,它“提高了多行插入和替换的性能”。看我的更新。太好了。谢谢我完全错过了。对于多次删除,您有什么建议?按照内噬菌体在原始帖子评论中的建议设置级联?@pocketfullofcheese:有时候级联删除是有意义的,在这种情况下,使用它们可以提高性能。但有时您可能不希望通过级联删除来避免意外的数据丢失,在这种情况下,您应该坚持当前的方法。我想大部分时间都是因为插入循环效率低下,而不是因为删除。这是一个非常明显的想法!真不敢相信我竟然没有想到。谢谢。这是个很明显的主意!真不敢相信我竟然没有想到。谢谢。太好了,正是我想要的。甜心,我真的需要这个太好了,正是我想要的。甜心,我真的需要这个