【问题标题】:Execute over 1000 insert statements in 1 string在 1 个字符串中执行 1000 多个插入语句
【发布时间】:2014-06-16 22:54:18
【问题描述】:

我认为这会很简单,但无论出于何种原因,当脚本完成时数据不在表中。我正在生成一个包含 1000 多个查询的字符串,目前是 1131 个,它们用“;”分隔。

这个字符串是由一个简单的for循环创建的:

query = ""

for: #loop condition
    query += "INSERT INTO Results (col1, col2, col3, col4, pass) VALUES ('%s', %s, %s, %s, 0);" % (val1, val2, val3, val4)
logger.debug("SQL Query = %s" % query)

try:
    cursor.execute(query, multi=True)
except MySQLdb.Error, e:
    try:
        logger.error("MySQL Error [%d]: %s" % (e.args[0], e.args[1]))
        dbinit.cnx.rollback()
        cursor.close()
        dbinit.cnx.close()
    except IndexError:
        logger.error("MySQL Error: %s" % str(e))
        dbinit.cnx.rollback()
        cursor.close()
        dbinit.cnx.close()

dbinit.cnx.commit()
cursor.close()
dbinit.cnx.close()

我没有收到任何错误,当我打印字符串时,它打印得很好。我什至可以复制/粘贴打印的内容,并一次运行所有 sql 命令,它运行得很好,所以我没有任何错误的查询。任何帮助表示赞赏,因为我很难过。我知道有其他方法可以解决这个问题,但如果有人也可以解释为什么这个方法不起作用,那么我可以学习,那也将不胜感激!

更新: Mike 的回答在很大程度上是正确的,但我只是想用我的代码最终的样子来更新这篇文章。

queryData=[]
for: #condition
    queryData.append((val1, val2, val3, val4, 0))

while len(queryData) != 0:
    cursor.executemany("INSERT INTO Results (col1, col2, col3, col4, pass) VALUES (%s, %s, %s, %s, %s)", queryData[:999])
    del queryData[:999]
dbinit.cnx.commit()

【问题讨论】:

  • 回滚关闭一切后是否允许提交?因为这就是你在异常情况下所做的事情。您让执行路径流出 try/catch 语句并执行最​​后 3 个命令。如果有什么事情失败了,我至少会在那个时候出现异常。
  • 它是单个字符串,但不是单个查询。许多提供程序不允许在单个查询中执行多个语句以防止 SQL 注入。如果它像这样INSERT INTO Results (col1, col2, col3, col4, pass) VALUES ('%s', %s, %s, %s, 0), ('%s', %s, %s, %s, 0), ('%s', %s, %s, %s, 0) ...,您可以将其作为单个查询执行(对不起,我不是 python 开发人员,但看起来这是可能的问题之一)
  • 没有发生异常,因此没有发生回滚和关闭。如果没有异常发生,最后 3 个命令执行得很好,但我仍然有一个空白表。我可以做不止一条语句,因为我可以复制/粘贴所有 1131 插入的字符串,并将其作为普通的 mysql 查询执行。您也不能在一次插入中包含超过 1000 个不同的 VALUES。
  • 您确定在尝试插入记录时检查的是同一数据库中的记录吗?
  • 是的....我确定。我只有一个。

标签: python mysql sql mysql-python


【解决方案1】:

看来您处理此问题的方式有误。 cursor.execute() 接受一个查询,准备它并使用您提供的数据执行它。在这一行

cursor.execute(query, multi=True)

您已经省略了第二个 params 参数,因此没有要执行的数据。

您似乎将 1000 多个查询组合为一个字符串。您或许可以使用cursor.query() 执行此操作,但是(如果可行)将导致服务器解析和准备基本相同的查询 1000 多次,效率较低。在任何情况下,许多 MySQL 类都明确禁止以这种方式组装多个查询。

您需要的是cursor.executemany(query, data),它构造了一个带有多个值集的单个查询,一个对应于data 的每一行。

我不是 Python 开发人员,我看不到您从哪里获取数据,但这是来自 MySQL reference 的示例,已重新设计:

data = [
  ('col1-1', 1,2,3),
  ('col1-2', 4,5,6),
  ('col1-3', 7,8,9),
]
stmt = "INSERT INTO Results (col1, col2, col3, col4, pass) VALUES ('%s', %s, %s, %s, 0)"
cursor.executemany(stmt, data)

您可以添加自己的异常处理。希望这可以帮助您入门。

注意:您可以通过这种方式插入的值集的数量没有限制,但是对您可以创建的字符串的长度有限制,默认情况下为 1Mb。如果您的要求超出此范围,您可以一次将插入批处理到 500 个并运行多个查询(3 个查询仍然比 1500 个更好!)或查看解析查询一次并为每个集合执行的 cursor.MySQLCursorPrepared 类您发送的数据。

【讨论】:

  • 使用 cursor.executemany() 的问题是 mysql 在一次插入中不支持超过 1000 个值,而我现在有 1131 个,并且预计会增长。我做了 cursor.execute(query, multi=True) 因为字符串查询中已经有数据(看看我构造字符串的方式),并且添加 multi=True 应该允许 cursor.execute 执行多个查询来自同一个字符串。 dev.mysql.com/doc/connector-python/en/…
  • cursor.executemany() 不包括单个insert 中的值。它发送一次查询以供服务器解析,然后根据您的值执行多次。您的方法类似,只是服务器必须解析整个查询 1000 多次。
  • 这不是 mysql 连接器文档所说的。这就是说 execute many 是单个插入,具有许多值。 INSERT INTO employees (first_name, hire_date) VALUES ('Jane', '2005-02-12'), ('Joe', '2006-05-23'), ('John', '2010-10-03') 是他们的例子,所以如果我需要插入超过 1000 个名称/日期对,它将不受支持。 dev.mysql.com/doc/connector-python/en/…
  • 我很抱歉 - 我误读了 MySQL 文档。 MySQLCursorPrepared 类按照我的建议进行。尽管如此,尽管 MySQL 可能有限制,但 Python 连接器文档中没有建议连接器有限制。可能是1000以内的批量发送数据,你试过了吗?
  • 脚本比较长,但我确实按照您的建议进行了更改,并且正在运行,我会报告。
猜你喜欢
  • 1970-01-01
  • 2020-12-07
  • 1970-01-01
  • 1970-01-01
  • 2019-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-31
相关资源
最近更新 更多