【问题标题】:How to optimise below sql query?如何优化下面的sql查询?
【发布时间】:2012-12-18 17:30:48
【问题描述】:

我在这里所做的是获取重复的预订和用户。此处预订票不能打印两次。如果用户打印带有该记录的工单跟踪器表更新。如果用户两次打印同一张票,则将其标记为重复。子查询在这里做的是返回一些被标记为重复的预订 id。

    SELECT t1.id AS res_id,
       t1.tx_id,
       t1.tx_date,
       t1.bx_date,
       t1.method,
       t1.theater_id,
       t1.showtime_id,
       t1.category_id,
       t1.amount,
       t1.fname,
       t1.status,
       t1.mobile,
       u.username,
       t2.*
FROM `reservation` AS t1
INNER JOIN
  ( SELECT *
   FROM `tracker`
   WHERE reservation_id IN
       ( SELECT reservation_id
        FROM `tracker`
        GROUP BY reservation_id HAVING ( METHOD = 1
                                        AND TYPE = 0
                                        AND COUNT(*) > 1 )
        OR ( METHOD = 1
            AND TYPE = 1
            AND COUNT(*) > 1 )
        OR ( METHOD = 2
            AND TYPE = 2
            AND COUNT(*) > 0 )
        OR ( METHOD = 3
            AND TYPE = 0
            AND COUNT(*) > 0 )
        OR ( METHOD = 3
            AND TYPE = 1
            AND COUNT(*) > 1 )
        OR ( METHOD = 3
            AND TYPE = 3
            AND COUNT(*) > 0 )) ) AS t2 ON t1.id = t2.reservation_id
INNER JOIN `users` AS u ON u.id = t2.user_id
WHERE t2.resolved = 0
  AND t2.duplicate = 1
ORDER BY t2.issue_date DESC, t1.id DESC

EXPLAIN 上述查询的命令。

我该怎么办?如果我索引应该使用哪些键?我如何决定要索引哪些键?我知道子查询会拖慢我的速度 我应该遵循哪些程序来消除速度缓慢?

【问题讨论】:

  • 请粘贴您的解释计划
  • 解释计划是什么意思?
  • 我在问题中贴了截图
  • GROUP BY reservation_id HAVING ... 部分看起来很可疑。 reservation_idtracker的主键吗?如果没有,HAVING method=1 AND type=0 将为这些列选择任意值,因为它们不包含在 GROUP BY 中。

标签: mysql sql database query-optimization


【解决方案1】:

在 MySQL 中,exists 子查询通常比 in 子查询快。你可以试试:

SELECT t1.id AS res_id, t1.tx_id, t1.tx_date, t1.bx_date,t1.method, t1.theater_id, t1.showtime_id,
       t1.category_id, t1.amount, t1.fname, t1.status, t1.mobile, u.username, t2.*
FROM `reservation` t1 INNER JOIN
     (SELECT *
      FROM `tracker` t
      WHERE EXISTS (SELECT 1
                    FROM `tracker` t3
                    where t3.reservation_id = t.reservation_id
                    GROUP BY reservation_id
                    HAVING (METHOD = 1 AND TYPE = 0 AND COUNT(*) > 1) OR
                           (METHOD = 1 AND TYPE = 1 AND COUNT(*) > 1) OR
                           (METHOD = 2 AND TYPE = 2 AND COUNT(*) > 0) OR
                           (METHOD = 3 AND TYPE = 0 AND COUNT(*) > 0) OR
                           (METHOD = 3 AND TYPE = 1 AND COUNT(*) > 1) OR
                           (METHOD = 3 AND TYPE = 3 AND COUNT(*) > 0)
                   )
     ) t2
     ON t1.id = t2.reservation_id INNER JOIN
     `users` AS u ON u.id = t2.user_id
WHERE t2.resolved = 0 AND t2.duplicate = 1
ORDER BY t2.issue_date DESC, t1.id DESC

我注意到子查询在having 子句中使用了隐藏列。它可能没有按照您的预期进行。通常,查询将在group by 子句中包含methodtype,或者具有诸如max(Method) 之类的表达式。

【讨论】:

  • 超级超级棒的优化。非常感谢。
  • 如果你能解释一下你在子查询中做了什么。我真的很想学习。
  • 我只是用exists (select 1 from (subquery with correlated where clause) 替换了构造in (subquery)。这是一个 hack,因为 MySQL 有时不会像现有的那样有效地优化 in
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-24
相关资源
最近更新 更多