[英]MySQL: Very slow update/insert/delete queries hanging on “query end” step
[英]Slow Update, Delete and Insert Queries under MariaDB
我們的服務器已從 Ubuntu 16 更新為 Ubuntu 20 和 MariaDB。不幸的是,網站的加載時間變慢了。 通常 MariaDB 應該比 Mysql 快。我發現,很簡單,網站上的更新命令有時需要大約 7 秒。 但是,如果我通過 myphpadmin 將這些更新命令直接輸入到數據庫中,它們只需要 0.0005 毫秒。
在我看來,MariaDB 經常出現更新命令時出現問題。 mysql 從來都不是問題。這是一個查詢示例:
UPDATE LOW_PRIORITY users
SET user_video_count = user_video_count + 1
WHERE user_id = 12345
數據庫格式為 MyISAM。
我不知道可能是什么原因。 你?
非常感謝你。
它可能像SELECT
在users
中搜索某些內容一樣簡單。 注意,InnoDB 不會遇到這個問題。
MyISAM
在執行UPDATE
、 INSERT
或DELETE
時必然會鎖定表。 (還有ALTER
和其他 DDL 語句。)如果有很多連接在執行寫入甚至SELECTs
的任何混合操作,那么鎖會級聯很長時間。
真正的解決方案,無論是在 MariaDB 還是 [尤其是] 在 MySQL 中,都是切換到 InnoDB。
如果這是對“喜歡”或“觀看次數”進行大量計數的情況,則部分解決方案(在任一引擎中)是將此類計數器放在一個單獨的並行表中。 這避免了那些簡單快速的更新與主表上的其他操作發生沖突。 在人流量極高的區域,收集此類增量並分批應用它們是有必要的。 我認為您的卷不需要那種激進的解決方案。
MySQL 幾乎消除了 MyISAM。 MariaDB 可能會在幾年后效仿。
為了解決這個問題:
myphpadmin 中的相同查詢非常快
問題不在於你如何運行它,而在於同時發生的其他事情。
( LOW PRIORITY
是 MyISAM 特定的 kludge,有時會起作用。)
MyISAM 進行“表鎖定”; InnoDB 做“行鎖定”。 因此,Innodb 可以在表上執行許多“同時”操作,而 MyISAM 會在寫入發生時立即序列化。
更多(現在專注於 InnoDB。)
可能涉及到的其他一些事情。
如果兩個UPDATEs
試圖同時修改同一行,一個將不得不等待(由於行鎖定)。
如果確實有大量事情在發生,延遲可能會一連串地發生。 如果在一個實例中有 20 個連接正在運行,那么它們各自都會減慢彼此的速度。 每個連接都被公平分配,但這意味着它們都變慢了。
SHOW PROCESSLIST
查看正在運行的程序——而不是“睡眠”。 “時間”最長的進程(系統線程除外)很可能是這場爭吵的始作俑者。
slowlog 可以幫助更深入地研究。 我打開它,使用足夠低的long_query_time
並等待“事件”發生。 然后我使用pt-query-digest
(或mydumpslow -st
)找出最慢的查詢。 通過更多的努力,人們可能會注意到有很多查詢在某一瞬間“緩慢”——甚至可能是“點查詢”(如UPDATE... WHERE id=constant
)意外地比long_query_time
運行得慢。 這表示太多查詢和/或某些意外鎖定行的查詢。 (注意:查詢的“時間戳”是查詢結束的時間;減去Query_time
即可開始。) SlowLog
更多的
正如您所發現的, innodb_flush_log_at_trx_commit = 2
在快速執行大量單查詢事務時是一個很好的修復。 如果該修復的頻率變得太大,那么我上面的評論可能就變得必要了。
=2 和 =0 之間不會有太大的性能差異。
至於innodb_flush_log_at_timeout
。 請提供 `SHOW GLOBAL STATUS LIKE 'Binlog%commits'
至於innodb_lock_wait_timeout
...我不認為改變它會對你有幫助。 如果您的查詢之一由於該超時而中止,您應該記錄它發生並重試事務。
聽起來您正在使用autocommit = ON
運行並且不使用顯式事務? 這很好(對於非金錢活動)。 在某些情況下,使用事務可以提高性能——例如人為地將多個查詢批處理在一起以避免某些 I/O。 缺點是與其他連接發生沖突的可能性增加。 盡管如此,如果您總是檢查錯誤並重新運行“事務”,那么一切都應該很好。
innodb_flush_log_at_trx_commit
當該設置為“1”(可能是您最初的設置)時,每個更新都會額外寫入磁盤以確保數據完整性。 如果磁盤是 HDD(而不是 SDD),則每次更新會增加大約 10 毫秒,因此導致每秒大約 100 次更新的最大值。 有幾種解決方法。
innodb_flush_log_at_trx_commit = 0 or 2
,犧牲一些數據完整性。我懷疑社交媒體巨頭會做上述所有事情。
當您使用 MariaDB 時,您可以使用像 EverSQL 這樣的工具來查找丟失的索引或發現冗余索引(例如,您在 user_video_count 上有一個您並不真正需要的索引)
首先我要感謝所有幫助過我的人。 我真的很感激人們嘗試投入寶貴的時間。
我想告訴您我是如何設法解決更新、插入和刪除查詢緩慢的問題的。
我將此值添加到 my.cnf 文件中:
innodb_flush_log_at_trx_commit = 2
在我重啟 mysql 服務器后,服務器負載突然下降,更新、插入和刪除查詢也從大約 0.22222 - 0.91922 秒下降到負載下的 0.000013 秒。 就像之前使用 Myisam 和 Mysql 一樣,以及它應該如何使用索引進行如此簡單的更新。
我不得不提一下,我已經將所有接收頻繁插入或更新命令的表設置為 INNODB,將那些有很多選擇的表設置為 ARIA。
由於我們不處理貨幣交易,如果我們因為以下原因而損失最后幾秒對我來說不是問題
innodb_flush_log_at_trx_commit = 2
我go更進一步。 如果我們輸掉了最后 30 秒,我也可以接受。
所以我也設置了:
innodb_flush_log_at_timeout = 30
我目前正在測試
innodb_flush_log_at_trx_commit = 0
但到目前為止,我沒有看到明顯的改善
innodb_flush_log_at_timeout = 30
innodb_flush_log_at_trx_commit = 0
代替
innodb_flush_log_at_timeout = 1 (default)
innodb_flush_log_at_trx_commit = 2
所以主要目標是:
innodb_flush_log_at_trx_commit = 2
or
innodb_flush_log_at_trx_commit = 0
有誰知道,為什么:
innodb_flush_log_at_timeout = 30
innodb_flush_log_at_trx_commit = 0
並不比剛才快
innodb_flush_log_at_trx_commit = 2
?
我也不明白,為什么這個設置沒有更受歡迎,因為如果許多網站不介意失去一秒鍾或更多時間,他們可以在速度方面有很大的改進。
非常感謝你。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.