2012-04-27 98 views
0

我有一个查询使用mysql中的子查询得到非常缓慢,花费几分钟,而我做的所有其他查询是非常快。MYSQL转换速度较慢的子查询(更快?)加入

因为我发现subquerys最有可能是一个坏主意,所以我想将 这个子查询转换为像我所有其他查询那样使用subquerys对性能产生重大影响的连接。

我的大部分其他查询都非常简单,但这个驱动我坚果。

这里是一个例子。

我有客户和账单。客户有多个账单。票据有州。账单有一个参数“无论”。

我需要更新 “里所有的账单都处于状态1或2的所有客户端和账单无论参数不是2”

因为我无法找到如何做到这一点我使用的转化是 “所有客户没有账单不处于状态1,并且不处于状态2,并且记录任何参数不是2的账单”

这些是我现在使用的subquerys的两个变体,一个使用count和一个使用“不在”,但他们似乎同样缓慢。

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中状态慢“复制到临时表”

我尝试了好几个小时,但我不能将它转换为没有那么慢的子查询有用的东西。 任何人都可以给我一个想法如何使用连接或比现在更快的事情做到这一点?

UPDATE

由于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 
+0

你能否确认下列内容......看起来你想更新所有在Bill表中存在的客户......并且不在“状态1”或“状态2”中..作为cl.id NOT IN的结果并查找Bill客户端NOT State1或State1。 – DRapp 2012-04-27 01:39:52

+0

我想更新所有有账单的客户(账单参考client.id),并且所有账单都处于状态1或状态2,这意味着没有更多的账单处于任何其他状态。 – dirk 2012-04-27 01:56:40

回答

0

要预先保证什么客户端将被包括在内,你可以运行在它自己的此查询...

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 
+0

嗯..这给了我所有的账单都不是状态1而不是状态2的客户。但我需要所有账单都处于状态1或状态2的所有客户,并且没有账单处于任何其他状态。这就是为什么我在第一个查询中使用了count的倒数,而在第二个查询中使用了“not in”。 – dirk 2012-04-27 02:10:50

+0

@dirk,检查修订版。内部查询执行OK状态的计数和另一个AnyOther状态。 HAVING将至少符合Ok State和AnyOther count = 0.只有问题我不知道如何应用是什么时候“whatever!='2'”组件。你只想要!='2'条目考虑的计数,或只有那些State1/State2,但希望这给你一个跳跃,我可以帮你缩小这个结果。 – DRapp 2012-04-27 02:21:22

+0

啊,非常感谢你,这就是它。然而,我已经把这个b.whatever!= 2放到了sum(if(b.state NOT IN(“state1”,“state2”)或b.whatever = 2,1,0))中,作为AnyOtherState。“完全是旧的查询。我现在将更新我的问题以包含答案。再次感谢! – dirk 2012-04-27 05:33:52