sql查询运行时间长

wtzytmuj  于 2021-06-25  发布在  Mysql
关注(0)|答案(2)|浏览(314)

我正在尝试运行此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)

但由于某些原因,返回任何结果需要14.8126秒。
测试时,它返回1行,我不明白为什么它这么慢。我相信这可能与连接有关,但我希望有人能帮助我,并指出正确的方向请?
我很抱歉,如果我错过了任何信息,所以请原谅我的无知。

dvtswwa3

dvtswwa31#

使用 EXPLAIN 看看执行计划。
查询已在对使用反联接模式 b .
我建议使用相同的反连接模式来代替 NOT IN 检查(反连接的大驼峰似乎让我们的大脑被它包围了;一旦我们了解了这个模式,我们就应该能够利用它。
像这样:

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输出的额外列中显示“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'
       )
ubby3x7f

ubby3x7f2#

除了其他答案,您还需要以下索引:

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' )
   )

相关问题