请帮助我使用Mysql慢查询分析

时间:2010-01-13 01:18:46

标签: mysql performance entity-attribute-value sql-execution-plan

我正在尝试分析这个mysql查询。它非常慢,这里的访问者表是大约50K条目,这个查询永远不会返回。当我尝试解释语句时,我发现索引没有在访问者表上使用,尽管索引可用。现在这是我需要帮助解决的难题。任何提示赞赏。

查询:

select distinct
  visitor0_.ID as ID130_,      

  case when visitor0_1_.id is not null then 1 when
  visitor0_.ID is not null then 0
  end as clazz_

from Visitor visitor0_ 
left outer join Operator visitor0_1_ on visitor0_.ID=visitor0_1_.id
where (visitor0_.ID not in
    (select operator1_.id 
     from Operator operator1_ 
     inner join Visitor operator1_1_ on operator1_.id=operator1_1_.ID))
  and (exists 
    (select visitorpro2_.ID 
     from VisitorProfileField visitorpro2_, ProfileField profilefie3_ 
     where visitorpro2_.profileFieldID=profilefie3_.ID 
       and visitorpro2_.visitorID=visitor0_.ID 
       and profilefie3_.name='subscription86' 
       and visitorpro2_.numberVal=1 
       and visitorpro2_.stringVal='Manual'))

解释输出屏幕截图: http://grab.by/grabs/9c3a629a25fc4e9ec0fa54355d4a092c.png

2 个答案:

答案 0 :(得分:2)

根据我推断的查询,以下内容应该产生相同的结果,没有子查询和更快的性能。

select v.ID as ID130_, 0 as clazz_
from Visitor v
left outer join (VisitorProfileField vpf join ProfileField pf 
                   on vpf.profileFieldID = pf.ID)
  on v.ID = vpf.visitorID and pf.name='subscription86' 
    and vpf.numberVal=1 and vpf.stringVal='Manual'
left outer join Operator o on v.ID = o.ID
where o.ID IS NULL;

如果我弄错了,请解释一下。您的NOT IN谓词似乎排除了与Visitor中任何ID匹配的任何Operator个ID。也就是说,子查询生成两个表中的所有 id的列表,因此NOT IN条件等同于Operator的外连接和o.ID IS NULL的简单测试{1}}。

这意味着您的选择列表中的CASE表达式毫无意义,因为如果您的条件仅匹配VisitorOperator中的任何行不匹配的行,它肯定会为0

我认为你的查询中存在一些问题。

此外,您似乎在VisitorProfileFieldProfileField表格中使用了EAV反模式。这会给你带来很多麻烦。

答案 1 :(得分:1)

你的查询是......大。你能解释一下它对你的影响吗?看起来它会拉出每个访客ID,以及他们是否是运营商,他们不是运营商,他们有特定的配置文件设置。这没有多大意义,所以我必须在那里遗漏一些东西。

这是我的尝试,基于我对你要做的事情的理解:

select distinct visitor.ID, IF(operator.id IS NOT NULL, 1, 0) AS clazz
from Visitor left outer join Operator on visitor.ID = operator.id
where not exists 
    (select 'x' from Operator OperatorTwo where OperatorTwo.id = visitor.ID)
and exists
    (select 'x' from VisitorProfileField, ProfileField
        where VisitorProfileField.profileFieldID = ProfileField.ID
        and VisitorProfileField.profileFieldID.visitorID = visitor.ID
        and VisitorProfileField.profileFieldID.numberVal = 1
        and VisitorProfileField.profileFieldID.stringVal = 'Manual'
        and ProfileField .name = 'subscription86')

似乎没有使用名为“operator1_1_”的联接表,您应该可以删除它。如果您正在使用它只是为了确保该表中的访问者有记录,我将使用exists而不是join。我放弃了。

我已经切换到了不存在,我认为MySQL可能更容易优化。我使用的是IF而不是一个案例,因为你只有两个,而且输入的时间更短。我不知道在MySQL上是否更快/更容易。

我可以告诉你,根据我的经验,MySQL性能会随着suqueries中的子查询而消失。它似乎放弃了优化它们并开始逐行运行它们。我敢打赌,如果您使用临时结果表(仅用于测试目的),您会发现查询运行得更快。

修改

比尔比我做得更远,我做得还不够。我喜欢比尔的询问,并同意他关于CASE陈述的结论,这有点让我失望。