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
,则填写id
和first_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 在一个查询中进行不同的更新?的主要内容,如果未能解决你的问题,请参考以下文章