【问题标题】:MYSQL converting slow update with subquery to (faster?) joinMYSQL 将带有子查询的慢速更新转换为(更快?)连接
【发布时间】:2012-05-07 18:47:52
【问题描述】:

我有一个使用 mysql 中的子查询的查询,它变得非常慢,最多需要几分钟,而我所做的所有其他查询都非常快。

我发现子查询很可能是个坏主意,所以我想转换 就像我对所有其他使用对性能有很大影响的子查询的查询所做的那样,这个子查询到一个连接。

我的大多数其他查询都非常简单,但这个让我抓狂。

这是一个例子。

我有客户和账单。客户有多个账单。法案有状态。账单有一个参数“随便”。

我需要更新 “所有账单都处于状态 1 或 2 并且账单参数不是 2 的所有客户”

由于我不知道该怎么做,所以我使用了 invert,它是 "所有没有账单的客户不在状态 1 和状态 2 中并且账单参数不是 2"

这是我现在使用的两个带有子查询的变体,一个使用 count,一个使用“not in”,但它们似乎同样慢。

update client cl , bill bi 
set cl.parameter = "parameter1" 
where cl.parameter="parameter2" 
    and bi.whatever != "2" 
    and bi.client_id = cl.id  
    and (select count(cl.id) 
            from bill bi 
                where bi.client_id = cl.id 
                    and bi.state!="state0" 
                    and bi.state != "state1" 
        ) = 0;

在 mysql 状态“发送数据”中变慢

update client cl , bill bi 
set cl.parameter = "parameter1"  
    where  cl.parameter="parameter2" 
        and bi.whatever != "2" 
        and bi.client_id = cl.id  
        and cl.id not in  (select distinct cl.id 
                                from bill bi  
                                    where bi.client_id = cl.id 
                                        and  ( bi.state!="state1" 
                                        and bi.state != "state2" 
                            ) ;

在 mysql 状态“复制到临时表”中变慢

我尝试了几个小时,但如果没有那个缓慢的子查询,我无法将其转换为有用的东西。 谁能给我一个想法,如何使用连接或比现在更快的方法来做到这一点?

更新

感谢 DRapp,这可以产生完全相同的结果并且速度更快。到目前为止,我可以测试的查询时间缩短到几秒钟,而之前是几分钟。

select
  c.id,
  sum( if( b.State IN ( "State1", "State2" ), 1, 0 )) as OkStatesCnt,
  sum( if( b.State NOT IN ( "State1", "State2" ) or b.whatever=2, 1, 0 )  ) as AnyOtherState
from
  client c
     join bill b
        ON c.id = b.client_id
where
  c.parameter = "parameter2"
   group by
      c.id
  having
      OkStatesCnt > 0
  AND AnyOtherState = 0

UPDATE client cl,
  ( full select query from above ) as PreQualified
 set cl.parameter = "parameter1"
 where cl.id = PreQualified.id

【问题讨论】:

  • 您能否确认以下内容...看起来您想要更新 Bill 表中存在的所有客户...并且不在“state1”或“state2”中...作为cl.id NOT IN 的结果并正在寻找 Bill 客户 NOT State1 或 State1。
  • 我想更新所有有账单的客户(账单引用了 client.id)并且所有账单都处于状态 1 或状态 2。这意味着没有更多的账单处于任何其他状态。

标签: mysql performance join subquery


【解决方案1】:

为了预先确保将包含哪些客户端,您可以自行运行此查询...

select
      c.id,
      sum( if( b.State IN ( "State1", "State2" ), 1, 0 )) as OkStatesCnt,
      sum( if( b.State IN ( "State1", "State2" ), 0, 1 )) as AnyOtherState
   from
      client c
         join bill b
            ON c.id = b.client_id
           AND b.whatever != "2"
   where
      c.parameter = "parameter2"
       group by
          c.id
   having
          OkStatesCnt > 0
      AND AnyOtherState = 0

如果这实际上是您正在寻找的,您可以像这样实施到您的更新中

UPDATE client cl,
      ( full select query from above ) as PreQualified
   set cl.parameter = "parameter1"
   where cl.id = PreQualified.id

【讨论】:

  • hm.. 这给了我所有账单不是 state1 且不在 state 2 的客户。但我需要所有账单都在 state 1 或 state 2 的所有客户,并且没有账单在任何其他状态。这就是为什么我在第一个查询中使用带有 count 的 invert 而在第二个查询中使用“not in”。
  • @dirk,检查修订。内部查询对 OK 状态和 AnyOther 状态进行计数。 HAVING 将至少符合 Ok State 和 AnyOther 计数 = 0。我不知道如何应用的唯一问题是“whatever!='2'”组件时。您只需要 != '2' 个条目来考虑计数,还是只需要 State1 / State2 的条目,但希望这能给您一个跳跃,我可以帮助您缩小结果范围。
  • 啊,非常感谢,就是这样。但是我已将 b.whatever!=2 放入“ sum( if( b.state NOT IN ( "state1","state2") or b.whatever=2, 1 , 0)) as AnyOtherState" 中。确切的旧查询。我现在将更新我的问题以包含答案。再次感谢!
猜你喜欢
  • 2016-03-02
  • 1970-01-01
  • 2017-10-09
  • 2021-03-28
  • 2018-03-31
  • 1970-01-01
  • 1970-01-01
  • 2012-07-20
  • 2022-11-11
相关资源
最近更新 更多