Mysql 优化SQL查询多个连接

Mysql 优化SQL查询多个连接,mysql,sql,query-optimization,Mysql,Sql,Query Optimization,我有一个带有嵌套联接的SQL查询: SELECT rh.host, rh.report, COUNT(results.id), COUNT(results_2.id), COUNT(results_3.id), COUNT(results_4.id) FROM report_hosts rh INNER JOIN report_results rr ON rh.report = rr.report LEFT OUTER JOIN results ON rr.result = results.id

我有一个带有嵌套联接的SQL查询:

SELECT rh.host, rh.report, COUNT(results.id), COUNT(results_2.id), COUNT(results_3.id), COUNT(results_4.id)
FROM report_hosts rh
INNER JOIN report_results rr ON rh.report = rr.report
LEFT OUTER JOIN results ON rr.result = results.id AND results.type =  'Hole' AND results.host = rh.host
LEFT OUTER JOIN results results_2 ON rr.result = results_2.id AND results_2.type =  'Warning' AND results_2.host = rh.host
LEFT OUTER JOIN results results_3 ON rr.result = results_3.id AND results_3.type =  'Note' AND results_3.host = rh.host
LEFT OUTER JOIN results results_4 ON rr.result = results_4.id AND results_4.type =  'Log' AND results_4.host = rh.host
GROUP BY rh.host
按原样查询大约需要5秒钟,99.7%的数据复制到临时表。完整查询的
解释显示如下:

+----+-------------+-----------+--------+---------------+---------+---------+-------------------+------+---------------------------------+
| id | select_type | table     | type   | possible_keys | key     | key_len | ref               | rows | Extra                           |
+----+-------------+-----------+--------+---------------+---------+---------+-------------------+------+---------------------------------+
|  1 | SIMPLE      | rr        | ALL    | report        | NULL    | NULL    | NULL              | 3139 | Using temporary; Using filesort |
|  1 | SIMPLE      | rh        | ref    | report        | report  | 5       | openvas.rr.report |  167 | Using where                     |
|  1 | SIMPLE      | results   | eq_ref | PRIMARY,type  | PRIMARY | 4       | openvas.rr.result |    1 |                                 |
|  1 | SIMPLE      | results_2 | eq_ref | PRIMARY,type  | PRIMARY | 4       | openvas.rr.result |    1 |                                 |
|  1 | SIMPLE      | results_3 | eq_ref | PRIMARY,type  | PRIMARY | 4       | openvas.rr.result |    1 |                                 |
|  1 | SIMPLE      | results_4 | eq_ref | PRIMARY,type  | PRIMARY | 4       | openvas.rr.result |    1 |                                 |
+----+-------------+-----------+--------+---------------+---------+---------+-------------------+------+---------------------------------+
当我删除
LEFT JOIN
s时,查询将在大约1s内执行,每个
LEFT JOIN
将增加大约1秒的执行时间

我的问题: 谁能解释一下,如果有更多的
左连接,为什么一个连接的复制到临时表任务需要更长的时间?MySQL是否为每个连接复制临时表数次

我怎样才能避免这种情况?我是否缺少索引

我打算实现的目标: 我有一张表,上面有几个主机的扫描结果。每个结果按类型分类(“孔”、“警告”、“注释”或“日志”)。我想选择每个主机以及相应数量的漏洞、警告、注释和日志。作为一个“限制”,我有一个事实,即不是每个主机都有每种类型的结果。

使用大量数据(在您的情况下,额外的
左连接将意味着将其存储在内存中

如果耗尽缓冲区,则需要将查询存储到驱动器上的临时结果表中

尝试使用相同数量的
左连接
s,但使用
限制
限制行数。它应该确认问题在于缓冲区(这意味着它将运行得更快)。

使用大量数据(在您的情况下,额外的
左连接将意味着将其存储在内存中

如果耗尽缓冲区,则需要将查询存储到驱动器上的临时结果表中


尝试使用相同数量的
左连接
s,但使用
限制
限制行数。它应该确认问题出在缓冲区中(这意味着它会运行得更快)。

您要多次连接一个表,这实际上就像连接多个表一样。您应该能够使用一些case语句和where子句来处理这个问题。(事实上,您可能不需要where子句。)


Case语句IME并不是最好的执行者,但是您在许多联接中的数据膨胀可能会抵消这一点,并提供更好的性能。

您多次联接一个表,这实际上就像联接多个表一样。您应该能够使用一些case语句和where子句来处理这个问题。(事实上,您可能不需要where子句。)


Case语句IME并不是最好的执行者,但是您从许多联接中获得的数据膨胀可能会抵消这一点,并提供更好的性能。

如果results1和results2都有10条匹配的记录,那么您现在有100条记录。每一个左连接都会进一步放大。这不是您要查找的查询。[我会发布更多,但我在打电话]如果结果1和结果2都有10条匹配记录,那么您现在有100条记录。每一个左连接都会进一步放大。这不是您要查找的查询。[我想发布更多,但我在打电话]我意识到,问题在于
左连接。使用
internal JOIN
s,速度要快得多,但我想我的查询在使用internal JOIN时是不可行的,是吗?internal JOIN主要处理较少的数据,这就是为什么它在直接比较中更快的原因。可行与否取决于您的需要<代码>左联接
获取左侧表中的所有值以及右侧表中的所有可用值(否则为空)<代码>内部联接
仅获取左侧的值,这些值在右侧具有对应项。正如YvesR所说,这意味着价值减少。我不知道你的表是用来做什么的,或者表中的数据是什么,所以我不能告诉你选择更多或更少的数据是否合适。我已经添加了我希望通过查询实现的目标。也许SQL不是实现这一点的最佳方式,我应该在我的编程语言中做“重”的部分。如果@Ilion建议的查询有效并产生您期望的结果,我会推荐它。我认识到,问题在于
左连接。使用
internal JOIN
s,速度要快得多,但我想我的查询在使用internal JOIN时是不可行的,是吗?internal JOIN主要处理较少的数据,这就是为什么它在直接比较中更快的原因。可行与否取决于您的需要<代码>左联接
获取左侧表中的所有值以及右侧表中的所有可用值(否则为空)<代码>内部联接
仅获取左侧的值,这些值在右侧具有对应项。正如YvesR所说,这意味着价值减少。我不知道你的表是用来做什么的,或者表中的数据是什么,所以我不能告诉你选择更多或更少的数据是否合适。我已经添加了我希望通过查询实现的目标。也许SQL不是实现这一点的最佳方式,我应该在我的编程语言中完成“繁重”的部分。如果@Ilion提出的查询有效并产生您期望的结果,我会推荐它。避免多重联接的好主意!查询只需1秒。但是,有一件奇怪的事情:如果我省略了
WHERE
子句,那么执行需要10秒以上的时间。
results
表有6000行,但只有600行与
WHERE
子句不匹配。如果
results.type
是一个索引,则在使用
WHERE
时,它们会计算索引值,而在不使用
WHERE
时,它会执行完整的表扫描。因此,原因是,只有
WHERE
子句可以“请求”一个索引,而不是聚合函数?避免多重连接的好主意!查询只需1秒。但是,有一件奇怪的事情:如果我省略了
WHERE
子句,那么执行需要10秒以上的时间。
results
表有6000行,但只有600行与
WHERE
子句不匹配。如果
results.type
是一个索引,则在使用
WHERE
时,它们会计算索引值,而在不使用
WHERE
时,它会执行完整的表扫描。因此,原因是,只有
WHERE
子句可以“请求”一个索引,但不是一个
SELECT rh.host, rh.report, 
 COUNT(CASE WHEN results.type = 'Hole' THEN 1 ELSE NULL END) as Holes, 
 COUNT(CASE WHEN results.type = 'Warning' THEN 1 ELSE NULL END) as Warnings,
 COUNT(CASE WHEN results.type = 'Note' THEN 1 ELSE NULL END) as Notes, 
 COUNT(CASE WHEN results.type = 'Log' THEN 1 ELSE NULL END) as Logs
FROM 
 report_hosts rh
INNER JOIN 
 report_results rr 
ON 
 rh.report = rr.report
LEFT OUTER JOIN 
 results 
ON 
 rr.result = results.id 
 AND results.host = rh.host
WHERE
 results.type = 'Hole' 
 OR results.type = 'Warning' 
 OR results.type = 'Note' 
 OR results.type = 'Log'
GROUP BY rh.host, rh.report