2014-10-07 60 views
0

我目前正在进行一些mysql查询的项目。项目中的所有mysql查询都是由其他开发人员完成的。不管怎么说,我跟他已经做了以下的查询有点混乱:如何提高这个mysql查询处理的速度

SELECT MIN(s_date) AS s_date, 
     client_id 
FROM tb1 
WHERE flag = 1 
    AND client_id NOT IN (
     SELECT DISTINCT client_id 
     FROM tb1 
     WHERE flag = 0 
    ) 
GROUP BY client_id; 

查询的第一部分,如果标志= 1,第二部分是检查不检查是(标志= 0)。我认为这是多余的,因为旗= 1,它不能是0.我不明白该查询的逻辑。而且我认为NOT IN有点慢(我的数据库需要2秒)。

请解释一下这个查询意味着什么,以及如何简化和改进它。

+1

使用EXPLAIN另一种创造性的选择查看你的查询使用了什么索引,然后考虑调整你的索引 – 2014-10-07 16:16:14

+2

你也可能发现使用JOIN查询比使用子查询更有效 – 2014-10-07 16:16:49

+0

@Mihai在不知道tb1的实际结构的情况下,我不能说对于某些;但最常见的做法是将'id'作为主键,'client_id'将是一个外键 – 2014-10-07 16:19:36

回答

1

您似乎总结了旗子从不0的客户端。查询更简单地写为:

SELECT MIN(s_date) s_date, 
     client_id F 
FROM tb1 
WHERE flag in (0, 1) 
GROUP BY client_id 
HAVING SUM(flag = 0) = 0; 

这也可能会提高性能。

+0

+1。与使用反连接或NOT EXISTS谓词的查询相比,此表单可能会提供更好的性能。通过这个查询,MySQL可能会有效地使用索引'ON tbl(client_id,s_date,flag)'。 – spencer7593 2014-10-07 16:35:45

+0

真棒,它只需要0.02秒得到相同的结果,欢呼声:) – agthumoe 2014-10-08 08:25:04

+0

但tbh,我真的不明白的代码,如果你不介意,请详细说明它。谢谢 – agthumoe 2014-10-08 08:26:14

0

在大多数数据库中,使用“不在”是简单,直观但缓慢的。有时候你可以这样解决:

where myfield in 
(select myfield 
where I want it 
minus 
select myfield 
where I want to exclude it) 

有些数据库使用除了而不是minus之外的单词。我不认为这与MySQL的工作,所以你必须做这样的事情:

select somefields 
from sometables 
left join (
select idfield, someOtherField 
from blah 
where I want to exclude it 
) temp on sometable on sometable.idfield = temp.idfield 
and temp.someOtherField is null 
0

这里是你怎么想起来:

IN子选择你发现的client_id的有名单至少有一条记录的标志位为0.

然后,您从主查询中排除该id列表。

所以,如果你有这样的样本数据:

client_id flag s_date 
--------- ---- ------ 
1   1  2014-01-01 
2   0  2014-02-01 
2   1  2014-03-01 
3   0  2014-04-01 
4   1  2014-05-01 
4   1  2014-06-01 

您的查询只会返回:

s_date  client_id 
------  --------- 
2014-01-01 1 
2014-05-01 4 

其实在您的查询,冗余使用的flag实际上是在主查询。它根本就不需要,因为你已经在子查询中消除了任何flag = 0值的所有client_id。

就优化查询而言。这是其中的一种情况,其中子查询可能比联接更快,也可能不是。这实际上取决于数据行的数量,符合子选择条件的那些行的数量等等(当然假设所有适当的索引都已经到位)。

你可以尝试自加入这样看执行更好地为您:

SELECT 
    MIN(a.s_date) AS s_date, 
    a.client_id AS client_id 
FROM tbl AS a LEFT JOIN (
    SELECT DISTINCT client_id 
    FROM tb1 
    WHERE flag = 0 
) AS b 
ON a.client_id = b.client_id 
WHERE b.client IS NULL 
GROUP BY a.client_id 

也可以尝试通过@GordonLinoff回答是获得这个同样的查询结果

+0

感谢您的解释,现在有道理。而你的代码真的有效。只需1秒即可获得结果。干杯 – agthumoe 2014-10-08 08:27:41