带有NOT IN的子查询 - MySQL中的超时

时间:2014-10-27 18:47:13

标签: mysql subquery

我在MySQL中遇到子查询问题。查询将进入超时状态:

SELECT mac FROM cc_btdata WHERE DATE(time)="2014-09-29" AND mac NOT IN (
SELECT mac FROM cc_btdata WHERE DATE(time) BETWEEN ("2014-09-29" - INTERVAL 60 DAY) AND ("2014-09-29" - INTERVAL 1 DAY) GROUP BY mac) GROUP BY mac

当我逐个调用查询时,它可以工作。但是当我把它们称为子查询时。我也在我的开发环境中尝试了MariaDB中的查询,但它在MySQL中无效。

此查询有什么问题?

谢谢!

3 个答案:

答案 0 :(得分:0)

我认为不需要GROUP BY mac,您也可以考虑将NOT IN替换为NOT EXISTS

SELECT mac 
FROM cc_btdata 
WHERE  NOT EXISTS (
SELECT 1 FROM cc_btdata 
WHERE DATE(time) BETWEEN ('2014-09-29' - INTERVAL 60 DAY) 
AND ('2014-09-29' - INTERVAL 1 DAY)
) 
AND DATE(time)='2014-09-29'

您可能还想发布查询执行计划(OR)解释计划。

答案 1 :(得分:0)

您可以像这样编写查询:

SELECT mac 
FROM cc_btdata b
WHERE NOT EXISTS (SELECT 1
                  FROM cc_btdata b2
                  WHERE b.mac = b2.mac AND
                        time >= '2014-09-29' - INTERVAL 60 DAY AND
                        time < '2014-09-29' - INTERVAL 1 DAY
                 ) AND
       time >= '2014-09-29' and time < '2014-09-29' + interval 1 day;

对于性能,您需要cc_btdata(mac, time)上的索引。我在没有date()的情况下重写了日期比较,因此MySQL将能够利用索引。

您也可以将其写为:

select mac
from cc_btdata
where time >= '2014-09-29' - INTERVAL 60 DAY 
group by mac
having sum(date(time) = '2014-09-29') > 0 and
       sum(date(time) between '2014-09-29' - interval 60 DAY and '2014-09-29' - interval 1 day) = 0;

(我使用了having子句的原始表达式,因为MySQL无法利用having子句的索引。)第一个版本可能会有更好的性能。

答案 2 :(得分:0)

我认为外连接在这种情况下会起作用并且会避免依赖子查询:

SELECT DISTINCT mac
FROM cc_btdata
LEFT JOIN cc_btdata cc_btdata_check ON 
cc_btdata.mac = cc_btdata_check.mac 
AND DATE(cc_btdata_check.time) 
BETWEEN ("2014-09-04" - INTERVAL 60 DAY) AND ("2014-09-04" - INTERVAL 1 DAY)
WHERE DATE(cc_btdata.time)="2014-09-04"
AND cc_btdata_check IS NULL