NOT EXISTS 条件下的查询速度问题
Query Speed Issue with NOT EXISTS condition
我有一个有效的查询,但速度很慢。有没有办法加快速度?基本上我有一个带有时间卡条目的 table,然后是第二个 table,带有该条目的时间细分,与 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
您似乎想知道 Timecardbreakdown table 中不存在的 TimecardID,此时您可以使用左外连接。
SELECT a.*
FROM Timecards a
LEFT OUTER JOIN TimecardBreakdown b ON a.TimecardID = b.TimecardID
WHERE b.TimecardID IS NULL
这将摆脱子查询(这是昂贵的)并使用连接(它更有效)。
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
列,那么查询处理程序将不得不返回主 table 以找到 Status
和 ID
的值。当这些列出现在索引中时,它会节省额外的操作。
如果您 SELECT
一组特定的列而不是 SELECT *
,将这些列包含在覆盖索引中可以显着提高查询性能。这是 SELECT *
被认为有害的几个原因之一。
(有些品牌和型号的 DBMS 有办法指定列的列表以在索引上运行而不实际索引它们。MySQL 要求您索引它们。但是覆盖索引仍然有帮助。)
我有一个有效的查询,但速度很慢。有没有办法加快速度?基本上我有一个带有时间卡条目的 table,然后是第二个 table,带有该条目的时间细分,与 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
您似乎想知道 Timecardbreakdown table 中不存在的 TimecardID,此时您可以使用左外连接。
SELECT a.*
FROM Timecards a
LEFT OUTER JOIN TimecardBreakdown b ON a.TimecardID = b.TimecardID
WHERE b.TimecardID IS NULL
这将摆脱子查询(这是昂贵的)并使用连接(它更有效)。
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
列,那么查询处理程序将不得不返回主 table 以找到 Status
和 ID
的值。当这些列出现在索引中时,它会节省额外的操作。
如果您 SELECT
一组特定的列而不是 SELECT *
,将这些列包含在覆盖索引中可以显着提高查询性能。这是 SELECT *
被认为有害的几个原因之一。
(有些品牌和型号的 DBMS 有办法指定列的列表以在索引上运行而不实际索引它们。MySQL 要求您索引它们。但是覆盖索引仍然有帮助。)