SQL 查询耗时较长 运行
SQL Query taking a long time to run
我正在尝试 运行 这个 SQL 查询:
SELECT
a.ticketnumber
FROM
ticket_updates a
LEFT JOIN
ticket_updates b
ON
b.ticketnumber = a.sequence AND b.type = 'reminder_complete'
WHERE
b.ticketnumber IS NULL AND
(a.type = 'reminder' OR a.type = 'reminder_high') AND
(a.for_agent = '' OR a.for_agent = '2') AND
a.notes <= '2018-05-10 23:00:00' AND
a.ticketnumber NOT IN (
SELECT ticketnumber
FROM ticket_updates
WHERE
type = 'reminder_complete' AND
ticketnumber = a.ticketnumber)
但由于某种原因,return 需要 14.8126 秒才能得到任何结果。
测试时,它 returning 1 行,我不明白为什么它这么慢。我相信这可能与连接有关,但我希望有人能帮助我并指出正确的方向?
如果我遗漏了任何信息,请原谅我的无知。
使用EXPLAIN
查看执行计划。
查询已经在为 b
使用反连接模式。
我建议使用相同的反连接模式来代替 NOT IN
检查。 (anti-join 的大驼峰好像把我们的脑袋都绕过去了;一旦我们理解了这个模式,我们应该就可以使用它了。
像这样:
SELECT a.ticketnumber
FROM ticket_updates a
-- anti-join
LEFT
JOIN ticket_updates b
ON b.ticketnumber = a.sequence
AND b.type = 'reminder_complete'
-- anti-join
LEFT
JOIN ticket_updates c
ON c.ticketnumber = a.ticketnumber
AND c.type = 'reminder_complete'
--
WHERE c.ticketnumber IS NULL
AND b.ticketnumber IS NULL
--
AND a.type IN ('reminder','reminder_high')
AND a.for_agent IN ('','2')
AND a.notes <= '2018-05-10 23:00:00'
就性能而言,我们需要确保有合适的索引可用。
考虑到 NOT IN (correlated subquery)
会增加执行时间,将其替换为反连接会使 MySQL 更有可能使用合适的索引(如果可用)。 (在性能方面,那些重复执行相关子查询会吃掉我们的午餐,如果我们不小心,也会吃掉我们的午餐盒。)
再次使用EXPLAIN
查看执行计划。
可以将反加入模式替换为 NOT EXISTS
以获得等效计划。 (与直觉相反,反连接模式有时会在 EXPLAIN 输出的 Extra 列中显示 "not exists",而 NOT EXISTS 则不会。)
我希望这会给出一个几乎等效的执行计划:
SELECT a.ticketnumber
FROM ticket_updates a
WHERE a.type IN ('reminder','reminder_high')
AND a.for_agent IN ('','2')
AND a.notes <= '2018-05-10 23:00:00'
AND NOT EXISTS
( SELECT 1
FROM ticket_updates b
WHERE b.ticketnumber = a.sequence
AND b.type = 'reminder_complete'
)
AND NOT EXISTS
( SELECT 1
FROM ticket_updates c
WHERE c.ticketnumber = a.ticketnumber
AND c.type = 'reminder_complete'
)
除了其他答案,您还需要这些索引:
a: (type, for_agent, notes, ticket_number)
a: (for_agent, type, notes, ticket_number)
ticket_updates: (type, ticket_number)
可能有助于结合LEFT JOIN
和NOT IN
:
AND NOT EXISTS
( SELECT 1
FROM ticket_updates b
WHERE b.ticketnumber IN ( a.sequence, a.ticketnumber )
AND b.type = 'reminder_complete' )
)
我正在尝试 运行 这个 SQL 查询:
SELECT
a.ticketnumber
FROM
ticket_updates a
LEFT JOIN
ticket_updates b
ON
b.ticketnumber = a.sequence AND b.type = 'reminder_complete'
WHERE
b.ticketnumber IS NULL AND
(a.type = 'reminder' OR a.type = 'reminder_high') AND
(a.for_agent = '' OR a.for_agent = '2') AND
a.notes <= '2018-05-10 23:00:00' AND
a.ticketnumber NOT IN (
SELECT ticketnumber
FROM ticket_updates
WHERE
type = 'reminder_complete' AND
ticketnumber = a.ticketnumber)
但由于某种原因,return 需要 14.8126 秒才能得到任何结果。
测试时,它 returning 1 行,我不明白为什么它这么慢。我相信这可能与连接有关,但我希望有人能帮助我并指出正确的方向?
如果我遗漏了任何信息,请原谅我的无知。
使用EXPLAIN
查看执行计划。
查询已经在为 b
使用反连接模式。
我建议使用相同的反连接模式来代替 NOT IN
检查。 (anti-join 的大驼峰好像把我们的脑袋都绕过去了;一旦我们理解了这个模式,我们应该就可以使用它了。
像这样:
SELECT a.ticketnumber
FROM ticket_updates a
-- anti-join
LEFT
JOIN ticket_updates b
ON b.ticketnumber = a.sequence
AND b.type = 'reminder_complete'
-- anti-join
LEFT
JOIN ticket_updates c
ON c.ticketnumber = a.ticketnumber
AND c.type = 'reminder_complete'
--
WHERE c.ticketnumber IS NULL
AND b.ticketnumber IS NULL
--
AND a.type IN ('reminder','reminder_high')
AND a.for_agent IN ('','2')
AND a.notes <= '2018-05-10 23:00:00'
就性能而言,我们需要确保有合适的索引可用。
考虑到 NOT IN (correlated subquery)
会增加执行时间,将其替换为反连接会使 MySQL 更有可能使用合适的索引(如果可用)。 (在性能方面,那些重复执行相关子查询会吃掉我们的午餐,如果我们不小心,也会吃掉我们的午餐盒。)
再次使用EXPLAIN
查看执行计划。
可以将反加入模式替换为 NOT EXISTS
以获得等效计划。 (与直觉相反,反连接模式有时会在 EXPLAIN 输出的 Extra 列中显示 "not exists",而 NOT EXISTS 则不会。)
我希望这会给出一个几乎等效的执行计划:
SELECT a.ticketnumber
FROM ticket_updates a
WHERE a.type IN ('reminder','reminder_high')
AND a.for_agent IN ('','2')
AND a.notes <= '2018-05-10 23:00:00'
AND NOT EXISTS
( SELECT 1
FROM ticket_updates b
WHERE b.ticketnumber = a.sequence
AND b.type = 'reminder_complete'
)
AND NOT EXISTS
( SELECT 1
FROM ticket_updates c
WHERE c.ticketnumber = a.ticketnumber
AND c.type = 'reminder_complete'
)
除了其他答案,您还需要这些索引:
a: (type, for_agent, notes, ticket_number)
a: (for_agent, type, notes, ticket_number)
ticket_updates: (type, ticket_number)
可能有助于结合LEFT JOIN
和NOT IN
:
AND NOT EXISTS
( SELECT 1
FROM ticket_updates b
WHERE b.ticketnumber IN ( a.sequence, a.ticketnumber )
AND b.type = 'reminder_complete' )
)