2014-10-27 56 views
0

我在MySQL中有一個子查詢問題。查詢運行到超時:NOT IN子查詢 - 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中。

這個查詢有什麼問題?

謝謝!

回答

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條款索引。)第一個版本可能會有更好的表現。

+0

謝謝你 - 你的第二個代碼的偉大工程,非常快。 – mittererr 2014-10-28 08:09:24

0

我看不出有任何需要GROUP BY mac,你也可以考慮與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' 

您可能還喜歡發佈查詢執行計劃更換NOT IN(OR)解釋計劃。

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