【问题标题】:Optimize Select query with mutiple JOINS, Sub queries and MIN MAX使用多个 JOINS、子查询和 MIN MAX 优化 Select 查询
【发布时间】:2019-10-09 09:35:42
【问题描述】:

我正在尝试优化以下查询,它运行良好但速度很慢。子查询多次遍历整个表

挑战在于,在 3 种情况下,我需要从值不为空的 JOINS 中获取最低值,而在 1 种情况下,JOIN 应该获得最高行值。我用过 MIN 和 Max

有没有更好的方法可以用来创建这个查询?

以下是值不为空的最低值列。我正在使用带有 JOIN 的 MIN() 子查询

j4.owner_perception, 
j6.tl_perception, 

以下是最高值列。我正在使用带有 JOIN 的 MAX() 子查询

j2.tl_perception, 
j2.owner_perception 

查询

EXPLAIN SELECT 
  s.ticket_number, 
  s.request_id,
  j4.owner_perception, 
  j6.tl_perception,
  j2.tl_perception, 
  j2.owner_perception 
FROM 
  survey 
  LEFT JOIN survey AS s ON survey.id = s.id 
  LEFT JOIN (
    SELECT 
      request_id, 
      MIN(id) AS minumumownerid 
    FROM 
      history_gt 
    WHERE 
      owner_perception != "" 
    GROUP BY 
      request_id
  ) AS j3 ON s.request_id = j3.request_id 
  LEFT JOIN history_gt AS j4 ON j4.id = j3.minumumownerid 
  LEFT JOIN (
    SELECT 
      request_id, 
      MIN(id) AS minumumtlid 
    FROM 
      history_gt 
    WHERE 
      tl_perception != "" 
    GROUP BY 
      request_id
  ) AS j5 ON s.request_id = j5.request_id 
  LEFT JOIN history_gt AS j6 ON j6.id = j5.minumumtlid 
  LEFT JOIN (
    SELECT 
      request_id, 
      MAX(id) AS maximumid 
    FROM 
      history_gt 
    GROUP BY 
      request_id
  ) AS j1 ON s.request_id = j1.request_id 
  LEFT JOIN history_gt AS j2 ON j2.id = j1.maximumid 
GROUP BY 
  s.request_id 
ORDER BY 
  s.id ASC 
LIMIT 
  50

这是解释细节(我不明白解释:)

+------+--------------+-------------+---------+-------------------+-------------+----------+--------------------+----------+----------------------------------------------+--+
|  id  | select_type  |   table     |  type   |  possible_keys    |    key      | key_len  |        ref         |  rows    |                    Extra                     |  |
+------+--------------+-------------+---------+-------------------+-------------+----------+--------------------+----------+----------------------------------------------+--+
|   1  | PRIMARY      | survey      | index   | NULL              | request_id  |     767  | NULL               |     476  | Using index; Using temporary; Using filesort |  |
|   1  | PRIMARY      | s           | eq_ref  | PRIMARY           | PRIMARY     |       4  | qo.survey.id       |       1  |                                              |  |
|   1  | PRIMARY      | <derived2>  | ref     | key0              | key0        |     153  | qo.s.request_id    |    1060  | Using where                                  |  |
|   1  | PRIMARY      | j4          | eq_ref  | PRIMARY           | PRIMARY     |       4  | j3.minumumownerid  |       1  | Using where                                  |  |
|   1  | PRIMARY      | <derived3>  | ref     | key0              | key0        |     153  | qo.s.request_id    |    2121  | Using where                                  |  |
|   1  | PRIMARY      | j6          | eq_ref  | PRIMARY           | PRIMARY     |       4  | j5.minumumtlid     |       1  | Using where                                  |  |
|   1  | PRIMARY      | <derived4>  | ref     | key0              | key0        |     153  | qo.s.request_id    |     530  | Using where                                  |  |
|   1  | PRIMARY      | j2          | eq_ref  | PRIMARY           | PRIMARY     |       4  | j1.maximumid       |       1  | Using where                                  |  |
|   4  | DERIVED      | history_gt  | range   | NULL              | request_id  |     152  | NULL               |  252406  | Using index for group-by                     |  |
|   3  | DERIVED      | history_gt  | index   | NULL              | request_id  |     152  | NULL               | 1009620  | Using where                                  |  |
|   2  | DERIVED      | history_gt  | index   | owner_perception  | request_id  |     152  | NULL               | 1009620  | Using where                                  |  |
+------+--------------+-------------+---------+-------------------+-------------+----------+--------------------+----------+----------------------------------------------+--+

【问题讨论】:

  • 根据提供的信息,几乎不可能说。请参阅:Why should I provide an MCRE for what seems to me to be a very simple SQL query?(尽管我会观察到没有 ORDER BY 的 LIMIT 几乎没有意义)
  • 另外,第一个 JOIN 似乎是多余的。
  • @Strawberry 已将查询缩小
  • @Sebastian 请修复格式问题(尤其是删除代码块中的所有前导空格;以便在不进行水平滚动的情况下看到更多内容)。此外,关于您的查询:您当前方法的问题在于,在派生表(From 子句中的子查询)中,正在扫描完整的表,然后在 JOIN 条件过滤后仅使用少量子查询结果。 一般情况下,在这些情况下,SELECT 子句中的相关子查询(具有适当的索引)可能会更有效。但请先修复格式..
  • @Madhur Bhaiya 我尝试删除 EXPLAIN 表之前的空格,但它只是作为文本出现

标签: mysql indexing query-optimization


【解决方案1】:

是的,您的原件体积庞大,并且要遍历历史记录表 3 次。我的建议是对历史记录中的所有记录进行一次条件查询。请注意我的“PQ”(预查询)按请求 id 分组,并根据 !=“” 资格的 CASE WHEN 执行相应的最小值/最大值。如果不适用,则返回 null 作为结果被忽略。然后我应用 coalesce() 来防止空值从该结果集中返回。现在我在 1 个结果集中拥有所有聚合。

现在可用,我将您多余的调查删除到调查 S 连接,并直接从调查转到预查询结果。现在,我可以将预查询中的连接返回到各自的最小/最大 ID 的历史记录。

SELECT 
      s.ticket_number, 
      s.request_id,
      j4.owner_perception, 
      j6.tl_perception,
      j2.tl_perception, 
      j2.owner_perception 
    FROM 
      survey s
         left join
         (SELECT 
                request_id, 
                coalesce( min( case when owner_perception != ""
                   then id else null end ), 0 ) minOwnerID,
                coalesce( min( case when tl_perception != ""
                   then id else null end ), 0 ) minTLID,
                MAX(id) AS maxID
             FROM 
                history_gt 
             GROUP BY 
                request_id ) PQ
            on s.request_id = PQ.request_id
             LEFT JOIN history_gt AS j4 
                ON PQ.minOwnerID = j4.id
             LEFT JOIN history_gt AS j6 
                ON PQ.minTLID = j6.id
             LEFT JOIN history_gt AS j2 
                ON PQ.maxID = j2.id
   GROUP BY 
      s.request_id 
   ORDER BY 
      s.id ASC 
   LIMIT 
      50

【讨论】:

    猜你喜欢
    • 2017-11-05
    • 1970-01-01
    • 1970-01-01
    • 2011-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-10
    • 1970-01-01
    相关资源
    最近更新 更多