簡體   English   中英

優化SQL查詢幾個JOIN

[英]Optimize SQL-Query several JOINs

我有一個帶有嵌套聯接的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%的副本復制到temp table 一個EXPLAIN完整查詢顯示為:

+----+-------------+-----------+--------+---------------+---------+---------+-------------------+------+---------------------------------+
| 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 ,查詢將在大約1秒內執行,每個LEFT JOIN增加大約一秒的執行時間。

我的問題:誰能解釋,如果有更多的LEFT JOIN ,為什么一個LEFT JOIN復制到臨時表任務會花費更長的時間? MySQL是否為每個JOIN多次復制臨時表?

如何避免這種情況? 我是否缺少索引?

我打算完成的工作:我有一個表,其中包含多個主機的掃描結果。 每個結果均按類型分類(“孔”,“警告”,“注釋”或“日志”)。 我要選擇每個主機以及相應數量的“孔”,“警告”,“注釋”和“日志”。 作為“限制”,我有一個事實,即並非每個主機都有每種類型的結果。

您要多次聯接單個表,這實際上就像聯接多個表一樣。 您應該能夠使用一些case語句和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

案例陳述(IME)並不是最出色的執行者,但是您因眾多聯接而導致的數據膨脹可能會抵消這種情況,從而提高性能。

使用大量數據(在您的情況下為額外的left join )將意味着將其存儲在內存中。

如果耗盡緩沖區,則查詢將需要存儲到驅動器上的臨時結果表中。

嘗試使用相同數量的left join秒,但限制了行數limit 它應該確認問題出在緩沖區中(這意味着它將運行得更快)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM