使用NOT EXISTS条件查询速度问题

时间:2016-11-30 19:46:44

标签: mysql datetime query-optimization correlated-subquery

我有一个有效的查询,但速度很慢。有没有办法加快速度?基本上我有一个带有时间卡条目的表,然后是第二个表,其中包含该条目的时间细分,与TimecardID相关。我正在寻找的是没有故障的时间块。我想如果我将标准降低到2个月就可以加快速度。谢谢你的帮助

SELECT * FROM Timecards
WHERE NOT EXISTS (SELECT TimeCardID FROM TimecardBreakdown WHERE Timecards.ID = TimecardBreakdown.TimeCardID) 
AND Status <> 0
AND DateIn >= CURRENT_DATE() - INTERVAL 2 MONTH

2 个答案:

答案 0 :(得分:2)

您似乎想知道TimecardBreakdown表中不存在的TimecardID,在这种情况下,您可以使用左外连接。

 SELECT a.*
 FROM Timecards a
 LEFT OUTER JOIN TimecardBreakdown b ON a.TimecardID = b.TimecardID
 WHERE b.TimecardID IS NULL

这将摆脱子查询(这是昂贵的)并使用连接(这是更有效的)。

答案 1 :(得分:0)

MySQL很快就会发现相关的子查询。尝试使子查询独立并加入它们。您可以使用LEFT JOIN ... IS NULL模式替换WHERE NOT EXISTS

SELECT tc.*
  FROM Timecards tc
  LEFT JOIN TimecardBreakdown tcb ON tc.ID = tcb.TimeCardId
 WHERE tc.DateIn >= CURRENT_DATE() - INTERVAL 2 MONTH
   AND tc.Status <> 0
   AND tcb.TimeCardId IS NULL

一些优化点。

首先,如果您可以将tc.Status <> 0更改为tc.Status > 0,则可以在该列上进行索引范围扫描。

其次,当您优化内容时,SELECT *被认为是有害的。相反,如果您可以只提供所需列的名称,事情就会更快。数据库服务器必须绕过您要求的所有数据;它无法判断你是否会忽略其中一些。

第三,Timecards (DateIn, Status, ID)上的复合索引将有助于此查询。该复合索引可用于满足您的查询条件的繁重生命。

这称为覆盖索引;它包含满足您的大部分查询所需的数据。如果您仅为DateIn列编制索引,则查询处理程序必须退回到主表以查找StatusID的值。当这些列出现在索引中时,它会保存额外的操作。

如果您SELECT某列而不是SELECT *,那么包括覆盖索引中的那些列可以显着提高查询性能。这是SELECT *被认为有害的几个原因之一。

(DBMS的一些品牌和型号有办法指定列表的列表,而不是实际索引它们.MySQL需要你索引它们。但覆盖索引仍然有帮助。)

阅读本文:http://use-the-index-luke.com/