一個接我們正在運行一個Web應用程序使用的查詢如下:優化MySQL查詢與若干個連接
SELECT
p.id, r.id AS report_id, tr.result_id,
r.report_date, r.department, r.reportStatus, rs.specimen,
tr.name, tr.value, tr.flag, tr.unit, tr.reference_range
FROM patients AS p
INNER JOIN
patients_reports AS pr ON pr.patient_id = p.id
INNER JOIN
reports AS r ON pr.report_id = r.id
INNER JOIN
results AS rs ON r.id = rs.report_id
INNER JOIN
test_results AS tr ON rs.id = tr.result_id
WHERE pr.patient_id = 17548
ORDER BY rs.specimen, tr.name, r.report_date;
解釋計劃是這樣的:
+----+-------------+-------+--------+---------------+-----------+---------+-------------------+--------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+-----------+---------+-------------------+--------+----------------------------------------------+
| 1 | SIMPLE | p | const | PRIMARY | PRIMARY | 4 | const | 1 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | rs | ALL | PRIMARY | NULL | NULL | NULL | 152817 | |
| 1 | SIMPLE | r | eq_ref | PRIMARY | PRIMARY | 4 | demo.rs.report_id | 1 | |
| 1 | SIMPLE | pr | eq_ref | PRIMARY | PRIMARY | 8 | const,demo.r.id | 1 | Using where; Using index |
| 1 | SIMPLE | tr | ref | result_id | result_id | 5 | demo.rs.id | 1 | Using where |
+----+-------------+-------+--------+---------------+-----------+---------+-------------------+--------+----------------------------------------------+
查詢返回27371行。目前test_results中有152730行。這只是少量的演示數據。
我試圖讓查詢更有效率,但我很難讓它更快地執行。我已經看過關於文檔和關於stackoverflow的問題的各種文章,但還沒有能夠解決這個問題。
我試圖消除的加入如下之一:
SELECT
pr.patient_id, r.id AS report_id, tr.result_id,
r.report_date, r.department, r.reportStatus, rs.specimen,
tr.name, tr.value, tr.flag, tr.unit, tr.reference_range
FROM patients_reports AS pr
INNER JOIN
reports AS r ON pr.report_id = r.id
INNER JOIN
results AS rs ON r.id = rs.report_id
INNER JOIN
test_results AS tr ON rs.id = tr.result_id
WHERE pr.patient_id = 17548
ORDER BY rs.specimen, tr.name, r.report_date;
的查詢計劃是那麼如下:
+----+-------------+-------+--------+---------------+-----------+---------+-------------------+--------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+-----------+---------+-------------------+--------+---------------------------------+
| 1 | SIMPLE | rs | ALL | PRIMARY | NULL | NULL | NULL | 152817 | Using temporary; Using filesort |
| 1 | SIMPLE | r | eq_ref | PRIMARY | PRIMARY | 4 | demo.rs.report_id | 1 | |
| 1 | SIMPLE | pr | eq_ref | PRIMARY | PRIMARY | 8 | const,demo.r.id | 1 | Using where; Using index |
| 1 | SIMPLE | tr | ref | result_id | result_id | 5 | demo.rs.id | 1 | Using where |
+----+-------------+-------+--------+---------------+-----------+---------+-------------------+--------+---------------------------------+
所以沒有太大的不同。
我已經嘗試重新排列查詢和使用STRAIGHT_JOIN等事物,但我沒有得到任何地方。
我很感激一些關於如何優化查詢的建議。謝謝。
編輯:啊!我並沒有對results.report_id指數,但它似乎並沒有幫助:
+----+-------------+-------+--------+-------------------+-----------+---------+-------------------+--------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-------------------+-----------+---------+-------------------+--------+---------------------------------+
| 1 | SIMPLE | rs | ALL | PRIMARY,report_id | NULL | NULL | NULL | 152817 | Using temporary; Using filesort |
| 1 | SIMPLE | r | eq_ref | PRIMARY | PRIMARY | 4 | demo.rs.report_id | 1 | |
| 1 | SIMPLE | pr | eq_ref | PRIMARY | PRIMARY | 8 | const,demo.r.id | 1 | Using where; Using index |
| 1 | SIMPLE | tr | ref | result_id | result_id | 5 | demo.rs.id | 1 | Using where |
+----+-------------+-------+--------+-------------------+-----------+---------+-------------------+--------+---------------------------------+
EDIT2:
patients_reports看起來是這樣的:
+------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------+------+-----+---------+-------+
| patient_id | int(11) | NO | PRI | 0 | |
| report_id | int(11) | NO | PRI | 0 | |
+------------+---------+------+-----+---------+-------+
EDIT3:
在添加results.report_id索引並按照@DRapp建議再次嘗試STRAIGHT_JOIN之後:
SELECT STRAIGHT_JOIN
r.id AS report_id, tr.result_id,
r.report_date, r.department, r.reportStatus, rs.specimen,
tr.name, tr.value, tr.flag, tr.unit, tr.reference_range
FROM patients_reports AS pr
INNER JOIN
reports AS r ON pr.report_id = r.id
INNER JOIN
results AS rs ON r.id = rs.report_id
INNER JOIN
test_results AS tr ON rs.id = tr.result_id
WHERE pr.patient_id = 17548
ORDER BY rs.specimen, tr.name, r.report_date;
的計劃是這樣的:
+----+-------------+-------+--------+-------------------+-----------+---------+-------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-------------------+-----------+---------+-------------------+------+----------------------------------------------+
| 1 | SIMPLE | pr | ref | PRIMARY | PRIMARY | 4 | const | 3646 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | r | eq_ref | PRIMARY | PRIMARY | 4 | demo.pr.report_id | 1 | |
| 1 | SIMPLE | rs | ref | PRIMARY,report_id | report_id | 5 | demo.r.id | 764 | Using where |
| 1 | SIMPLE | tr | ref | result_id | result_id | 5 | demo.rs.id | 1 | Using where |
+----+-------------+-------+--------+-------------------+-----------+---------+-------------------+------+----------------------------------------------+
所以我認爲,看起來好多了,但我不知道到底如何告訴。此外,查詢似乎仍然與以前大致相同。
如果您刪除,會發生什麼ORDER BY子句,或至少'specimen'排序?你似乎把所有的行都從'results'中拉出來,而你並不需要它們。 –
這聽起來像是你要求27371/152730 =〜18%的數據。我錯過了什麼嗎?全面掃描非常有可能是拉動18%任何數據集的最快方法。 (還有一個我試圖給出的答案,這就是「嘗試PostgreSQL」) – derobert
@Larry Lustig:刪除ORDER BY似乎沒有什麼區別。 – Wodin