【问题标题】:Updating multiple rows in one query very slow performance在一个查询中更新多行性能非常慢
【发布时间】:2011-11-25 19:14:03
【问题描述】:

我正在寻找使用单个查询一次更新多行的最佳方法。 目前我有:

UPDATE `profiles` SET `name` = CASE `id` WHEN 1 THEN 'John' WHEN 2 THEN 'Jane' END, `gender` = CASE `id` WHEN 1 THEN 'Male' WHEN 2 THEN 'Female' END WHERE `id`=1 OR `id`=2

但这需要大约 4 分钟才能完成(我的实际查询是针对 2000 万行数据库中的 10 个字段),而单个更新查询大约需要 1 秒。

我正在尝试找出原因,实际发生了什么?我认为通过在 WHERE 子句中指定 id 可以加快速度。

【问题讨论】:

  • 快速拍摄。我会为此准备 2 个不同的查询。即使您指定了WHERE 'id'=1 OR 'id'=2,使用CASE 方法也会强制mysql 收集您的所有ID。如果您直接使用唯一的id 为每个案例准备一个查询,您将拥有最快的方法来执行此操作。通过使用 2 个语句,您还可以获得更清晰的查询,因为这种 CASE 方法使查询有点奇怪......; )

标签: php mysql sql centos


【解决方案1】:

你有关于 id 的索引吗?如果没有,最好创建一个(警告,这可能需要很长时间,请在非高峰时间进行):

CREATE INDEX id_idx ON profiles (id);

顺便说一句,对表中 2000 万行的 10 个字段进行查询可能需要很长时间,尤其是在没有索引或缓存很冷的情况下。

更新:为了测试,因为我很好奇,我试图重现你的情况。为此,我制作了一些测试数据。

DDL:https://gist.github.com/b76ab1c1a9d0ea071965
更新查询:https://gist.github.com/a8841731cb9aa5d8aa26
用测试数据填充表的 Perl 脚本:https://gist.github.com/958de0d848c01090cb9d

但是,正如我在下面的评论中已经提到的,Mysql 将阻止您插入重复数据,因为 id 是您的主键,但不是唯一的。如果您可以评论表架构和/或发布您的 DDL,这将有很大帮助。

祝你好运! 亚历克斯。

【讨论】:

  • id 的值为 1 或 2 并且可能多次出现,我是否正确理解?这并不是创建密钥的有效方法。您在表中没有可以作为主键的唯一 id 吗?
  • 在破解一些测试脚本时,我注意到如果 id 不是唯一的,Mysql(正确地)会阻止我插入数据。你能和我们分享一下 DDL 表吗,DESCRIBE profiles 是吗?
  • 您确定密钥是 PRIMARY 吗?或者它只是一个简单的键?因为 PRIMARY KEY 不允许碰撞。
【解决方案2】:

请您发布配置文件表的 DDL 好吗?这将有助于查看您设置了什么样的索引(例如 - 我们可以假设 id 列是这里的主键吗?)。如果您使用的是 MySQL,那么只需运行“SHOW CREATE TABLE profiles”来生成 DDL。

有几点可能会有所帮助:

1) 尝试在 WHERE 子句中使用 BETWEEN 而不是 OR。例如 更新profiles

SET `name` = 

CASE `id` WHEN 1 THEN 'John' 

WHEN 2 THEN 'Jane' END, 

`gender` = CASE `id` 

WHEN 1 THEN 'Male' WHEN 2 THEN 'Female' END 

WHERE `id` between 1 and 2;

2) 尝试将查询拆分为单独的查询,以避免使用 CASE 语句,例如

update `profiles`

set `name` = 'John',

    `gender` = 'Male'

where `id` = 1;

update `profiles`

set `name` = 'Jane',

    `gender` = 'Female'

where `id` = 2;

我不知道这是否可行,因为我不确定您在什么情况下使用该查询!希望对您有所帮助。

【讨论】:

    【解决方案3】:

    能否请您指定所有字段的所有案例,以便我们有更好的主意。如果您有修复案例仅针对 id=1 和 2 进行更新,则将您的查询拆分为 2 个查询,例如:

    update `profiles` set `name` = 'John', `gender` = 'Male' where `id` = 1; 
    update `profiles` set `name` = 'Jane', `gender` = 'Female' where `id` = 2; 
    

    【讨论】:

    • 我知道我可以单独运行这些,我追求的是一种在一个查询中运行它们的方法。
    猜你喜欢
    • 1970-01-01
    • 2017-09-02
    • 1970-01-01
    • 2015-07-10
    • 2017-11-17
    • 2021-12-18
    • 1970-01-01
    • 2021-05-24
    • 1970-01-01
    相关资源
    最近更新 更多