简体   繁体   English

MYSQL将带有子查询的缓慢更新转换为(更快?)联接

[英]MYSQL converting slow update with subquery to (faster?) join

I have a query that uses a subquery in mysql that gets very slow, taking up to a few minutes while all other querys i do are quite fast. 我有一个查询,该查询使用mysql中的子查询变得非常慢,最多需要几分钟,而我所做的所有其他查询都相当快。

As i found out subquerys are most likely a bad idea so i wanted to convert this subquery to a join like i did with all my other querys that used subquerys with big impacts on performance. 正如我发现的那样,子查询很可能不是一个好主意,所以我想将此子查询转换为联接,就像我对所有其他使用子查询的查询所做的一样,这对性能产生了很大影响。

Most of my other querys where quite simple but this one drives me nuts. 我的大多数其他查询都非常简单,但这让我很生气。

Here is an example. 这是一个例子。

I have clients and bills. 我有客户和账单。 Clients have multiple bills. 客户有多个账单。 Bills have states. 法案有州。 And bills have a parameter "whatever". 并且账单具有参数“ whatever”。

I need to update "all clients where all bills are in state 1 or 2 and that bills whatever-parameter is not 2" 我需要更新“所有帐单都处于状态1或2且帐单无论参数不是2的所有客户端”

Since i couldnt find out how to do that i used the invert which is "all clients that have no bills that are not in state 1 and not in state 2 and that bills whatever-parameter is not 2" 由于我无法找到解决方法,因此我使用了反转功能,即“所有没有帐单的客户都不在状态1和状态2,并且帐单的任何参数不是2”

These are the two variants with subquerys i am using right now,one using count and one using "not in", but they seem to be equally slow. 这是我现在正在使用的带有子查询的两个变体,一个使用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;

gets slow in mysql state "sending data" 在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" 
                            ) ;

gets slow in mysql state "copying to temp table" 在mysql状态“复制到临时表”中变慢

I tried for hours but i couldn't convert this to something usefull without that slow subquery. 我尝试了几个小时,但没有该慢速子查询,我无法将其转换为有用的东西。 Can anyone give me an idea how to do this using a join or something faster than now? 任何人都可以给我一个想法,如何使用联接或比现在更快的速度执行此操作?

UPDATE 更新

Thanks to DRapp, this produces the exact same results and is much faster. 多亏了DRapp,这产生了完全相同的结果,并且速度更快。 For what i could test till now query time is down to a few seconds, and it was a few minutes before. 对于我到目前为止可以测试的内容,查询时间减少到几秒钟,而几分钟之前。

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

And

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

To pre-ensure WHAT clients will be included, you can run this query on its own... 为了预先确保将包括哪些客户端,您可以单独运行此查询...

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

IF this in-fact IS what you are looking for, you can just implement into your update like 如果实际上是您要查找的内容,则可以将其实施到更新中,例如

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM