【发布时间】: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