首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >请帮我做一下Mysql慢查询分析

请帮我做一下Mysql慢查询分析
EN

Stack Overflow用户
提问于 2010-01-13 09:18:46
回答 2查看 476关注 0票数 2

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

查询:

代码语言:javascript
复制
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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-01-13 10:01:59

根据我对您的查询的推断,下面的语句应该会产生相同的结果,没有子查询,并且性能更快。

代码语言:javascript
复制
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谓词似乎排除了与Operator中的任何id匹配的任何Visitor id。也就是说,子查询生成两个表中所有id的列表,因此NOT IN条件相当于到Operator的外连接和一个简单的测试where o.ID IS NULL

这意味着选择列表中的CASE表达式是没有意义的,因为如果您的条件只匹配与Operator中的任何行都不匹配的Visitor行,那么它肯定是0。

我认为您的查询中有一些严重的混淆。

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

票数 2
EN

Stack Overflow用户

发布于 2010-01-13 09:51:27

您的查询是...大的。你能解释一下它对你有什么好处吗?它看起来像是拉取每个访问者ID,以及他们是否是操作员,其中他们不是操作员,并且他们有特定的配置文件设置。这不是很有意义,所以我一定是漏掉了什么。

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

代码语言:javascript
复制
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。我把它弄丢了。

我已经把你的not换成了not exists,我觉得这对MySQL来说可能更容易优化。我用IF代替大小写,因为你只有两个大小写,而且输入起来更短。我不知道哪一个在MySQL上更快/更容易。

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

编辑:

比尔比我走得更远,我走得还不够远。我喜欢比尔的质疑,并同意他关于案件陈述的结论,这有点让我吃惊。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2053757

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档