PyMySQL 在一个查询中进行不同的更新?

Posted

技术标签:

【中文标题】PyMySQL 在一个查询中进行不同的更新?【英文标题】:PyMySQL different updates in one query? 【发布时间】:2016-05-10 10:06:47 【问题描述】:

所以我有一个 python 脚本,它遍历大约 350,000 个数据对象,并且根据一些测试,它需要更新代表 mysql db 中每个对象的行。我也在使用 pymysql,因为我遇到的麻烦最少,尤其是在发送大型选择查询时(带有 where column IN (....) 子句的选择语句可以包含 100,000+ 个值)。

由于每行的每次更新都可能不同,因此每个更新语句都是不同的。例如,对于某一行,我们可能想要更新 first_name,但对于另一行,我们希望保持 first_name 不变,我们想要更新 last_name

这就是我不想使用cursor.executemany() 方法的原因,该方法接受一个通用更新语句,然后将值提供给它,但是正如我所提到的,每次更新都是不同的,因此拥有一个通用更新语句不会真的很适合我的情况。我也不想通过网络单独发送超过 350,000 条更新语句。无论如何,我可以将所有更新语句打包在一起并立即发送吗?

我尝试将它们全部放在一个查询中并使用cursor.execute() 方法,但它似乎并没有更新所有行。

【问题讨论】:

有多少种不同的更新?即,您使用百万分之三的值更新了多少个不同的表?这些表上有多少不同的列?即它只是几个不同的更新语句吗? 除了“一个查询”或“百万分之一”查询之外,还有其他有用的选项吗?如果数据被加载到数据库中的work table 并从中进行操作呢?数据库喜欢玩表中的数据? @RyanVincent 他们都只是更新同一个表,但是该表有 12 列,每个更新语句可以一次更新任何不同的列组合,从 1 列到 10 列。 您能否编写更新语句以使用新值或现有值更新任何列?这会给您一种处理新值的方法吗? 这取决于测试及其复杂程度。您可以通过拆分每个测试来为每列编写 1 个大语句或 10、1 个 .. 或更多。可以分享一下测试吗?在一个表中以这种行依赖的方式定期更新 350,000 行也很奇怪!也许可以使用不同的数据库结构? 【参考方案1】:

SQL #1:CREATE TABLE t 包含您可能需要更改的任何列。将它们全部设为NULL(而不是NOT NULL)。

SQL #2:对所有需要的更改进行批量INSERT(或LOAD DATA)。例如,如果只更改first_name,则填写idfirst_name,但其他列有NULL

SQL #3-14:

UPDATE real_table
  JOIN t  ON t.id = real_table.id
  SET real_table.first_name = t.first_name
  WHERE t.first_name IS NOT NULL;
# ditto for each other column.

除了 #1 之外的所有 SQL 都非常耗时。而且,由于UPDATE 需要构建撤消日志,它可能会超时或出现问题。如有必要,请参阅a discussion of chunking。

如有必要,使用COALESCE()GREATEST()IFNULL()等函数。

大量 UPDATEs 通常意味着架构设计不佳。

(如果 Ryan 加入“答案”而不是“评论”,他可能应该得到“赏金”。)

【讨论】:

嗨 Rick,我知道你回答了我关于 mysql 连接器的其他问题,但是当我尝试使用 pymysql 库加载数据本地 Infile 时遇到类似的错误。无论我是从我的机器还是从数据库是 RDS 数据库的 EC2 机器运行代码,我都会收到 Broken Pipe 错误,所以我怀疑网络已经连续一周那么糟糕e_bytes raise err.OperationalError(2006, "MySQL server has gone away (%r)" % (e,)) pymysql.err.OperationalError: (2006, "MySQL server has gone away (BrokenPipeError(32, 'Broken pipe'))")【参考方案2】:

如果您可以将“测试”编码到 SQL 逻辑本身中,那么您的最佳表现将是,因此您可以将所有内容归结为几个 UPDATE 语句。或者至少尽可能多地这样做,这样需要单独更新的行就更少了。

例如:

UPDATE tablename set firstname = [some logic]
WHERE [logic that identifies which rows need the firstname updated];

您对测试的描述不多,因此很难确定。但是你通常可以通过一些工作在 WHERE 子句中获得相当多的逻辑。

另一种选择是将您的逻辑放入存储过程中。您仍将进行 350,000 次更新,但至少它们并非全部“越界”。不过,我只会将其用作最后的手段;业务逻辑应尽可能保留在应用程序层中,而存储过程会降低您的应用程序的可移植性。

【讨论】:

以上是关于PyMySQL 在一个查询中进行不同的更新?的主要内容,如果未能解决你的问题,请参考以下文章

python pymysql 怎么让查询返回的字典

使用pymysql进行定时查询数据不更新的原因及解决方式

Python通过pymysql连接数据库并进行查询和更新SQL方法封装

Django学习

Windows系统下python3中安装pyMysql

数据库:数据库引擎索引pymysql