为啥连接器/Python 不执行许多优化插入?
Posted
技术标签:
【中文标题】为啥连接器/Python 不执行许多优化插入?【英文标题】:Why isn't Connector/Python executemany optimizing inserts?为什么连接器/Python 不执行许多优化插入? 【发布时间】:2017-05-01 17:55:04 【问题描述】:我正在使用连接器/Python 将许多行插入到 mysql 的临时表中。这些行都在列表列表中。我像这样执行插入:
cursor = connection.cursor();
batch = [[1, 'foo', 'bar'],[2, 'xyz', 'baz']]
cursor.executemany('INSERT INTO temp VALUES(?, ?, ?)', batch)
connection.commit()
我注意到(当然还有更多行)性能极差。使用 SHOW PROCESSLIST,我注意到每个插入都是单独执行的。但是文档https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-executemany.html 说这应该优化为 1 个插入。怎么回事?
【问题讨论】:
dev.mysql.com/doc/connector-python/en/… "此方法执行给定的数据库操作(查询或命令)。在元组或字典参数中找到的参数与操作中的变量绑定。使用 %s 或 % 指定变量(name) 的参数样式(即使用 format 或 pyformat 样式)。如果 multi 为 True,则 execute() 返回一个迭代器。”有没有?光标 api 中的占位符。 然而,该语句与“?”一起工作 100%。我使用它是因为其他开发人员在现有代码中使用它。奇怪的是它有点有效。 api 本身支持各种占位符,也许某个地方的一些通用功能正在捕获它们?无论哪种方式,您实际上都可以查询占位符 python.org/dev/peps/pep-0249/#paramstyle 的实现本身。对于 mysql 连接器,您应该始终使用 %s 或命名参数。 是的,现在我明白了,但我不能是唯一一个受到这个打击的人。我知道 %s 是正确的占位符,但我看到所有这些代码都使用 ?并且工作正常。 唯一的问题是 executemany() 优化。 我只是希望帮助某人解决“天哪,使用问号占位符很好,除了 executemany() 没有做我想做的事”的问题。你会看到人们在 python 中到处使用问号占位符。 【参考方案1】:回答这样其他人就不会进行我必须进行的调试!
我在我们代码中的其他查询上编写了查询建模,这些查询使用了准备好的语句并使用了“?”来表示参数。但是对于 executemany(),您不能这样做!它必须使用“%s”。更改为以下内容:
cursor.executemany('INSERT INTO temp VALUES(%s,%s,%s)', batch)
...速度提高了一百倍,使用 SHOW PROCESSLIST 可以看到优化的单个查询。当心标准“?”语法!
【讨论】:
在大多数情况下,您仍应使用准备好的语句来避免 SQL 注入。 mysql 中内置了许多其他机制来促进批量插入。最值得注意的是 LOAD DATA INFILE,这会比你的执行速度快很多 @e4c5 有问题的陈述正确引用。我不确定海报使用的是什么但 %s 不是?是整个mysql连接器游标api的值占位符。 这正是我要说的。我现在知道 %s 是正确的占位符,但只是因为 '?'没有优化,不是因为它不起作用。 ?工作得很好。这就是调试的巨大痛苦。 我是说你应该为了安全而牺牲速度增益,因为有更快的方法来导入大量数据 这与安全无关。这不是字符串格式,它们是占位符。【参考方案2】:尝试打开这个命令: cursor.fast_executemany = True
否则 executemany 就像多次执行一样
【讨论】:
cursor.fast_executemany
是一个pyodbc功能。这个问题是关于 MySQL Connector/Python 的。【参考方案3】:
如果您像cursor.executemany('INSERT IGNORE INTO temp VALUES(%s,%s,%s)', batch)
一样使用IGNORE
,executemany()
的行为就像多次执行!
【讨论】:
以上是关于为啥连接器/Python 不执行许多优化插入?的主要内容,如果未能解决你的问题,请参考以下文章