今天,我們遇到了由這個確切查詢引起的主要性能問題(當然名稱不同):
UPDATE foo
LEFT JOIN bar
ON bar.foo_id = foo.id
SET foo.flag = 1
WHERE bar.foo_id IS NULL;
該軟體是第三方的,我們沒有撰寫代碼或資料庫架構。
foo有 42k 行,bar有 130k。一個特別的foo.id事情經常發生在bar.foo_id。(bar是一個在foo和之間實作 m:n 關系的關系表qux。幾乎每一行都qux與特定foo行有關系,然后與它獨有的幾個關系。可能有更多的重復,可能并不重要。)一個索引上foo.id存在。bar.foo_id是索引的一部分,也包含bar.qux_id和不相關的bar.text。
該查詢在db.t3.medium使用 Aurora MySQL 5.7的實體的100% CPU 下運行了 55 分鐘。慢日志指出Rows_examined: 5719954827。
有人可以解釋這個數字的確切原因以及由此產生的低性能是什么嗎?42k * 130k 接近它,因此可能與它有關。
在我們的例子中,我們可以簡單地GROUP BY foo_id然后加入結果而不是bar解決問題。但是,這在所有情況下都不可能 - 而且我認為創建索引不會產生bar.foo_id影響,因為NULL值只能由于JOIN陳述句而發生。
該EXPLAIN輸出是如下:
id|select_type|table |partitions|type |possible_keys|key |key_len|ref|rows |filtered|Extra |
-- ----------- ----------------- ---------- ----- ------------- --------------------- ------- --- ------ -------- ------------------------
1|UPDATE |foo | |ALL | | | | | 42921| 100.0| |
1|SIMPLE |bar | |index| |uidx_qux_foo |780 | |129465| 10.0|Using where; Using index|
據我所知,EXPLAIN PLAN在 MySQL 中不可用。
uj5u.com熱心網友回復:
您只在一張表中寫入欄位,即 aptly-named foo,因此將您的查詢寫入該表中僅查找/掃描一次:
update foo set flag = 1 where ...
相反,您撰寫的內容是您的兩個(三個?)表的乘積,然后為結果行中的每一個設定值。這是不必要的浪費,因為同樣,您只想在foo表中每行最多設定一次資料。
一旦你修復了你的整體邏輯,剩下的就是最典型的資料庫訪問模式:為你的select陳述句提供正確的索引(即where上面后面的部分)。一個簡單的explain plan應該告訴你到底是什么問題,如果有的話。你的帖子在這里根本沒有幫助。
uj5u.com熱心網友回復:
Rows_examined: 5719954827 是一個強有力的指標。
將查詢更改為此“半連接”。它不需要重復設定 foo.flag,但在 foo 中每行只執行一次 int。
UPDATE foo
SET foo.flag = 1
WHERE NOT EXISTS ( SELECT 1 FROM bar
WHERE bar.foo_id = foo.id );
這可能會給您類似于“檢查的 84K 行”(84K = 2*42K)之類的資訊。
而且bar 確實需要一個INDEX 起點用foo_id。
為什么需要這個標志?為什么需要一次更改很多行?你不能以其他方式設計應用程式嗎?
如需進一步討論,請提供SHOW CREATE TABLE。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/365709.html
