一紧阔、全表掃描對 server 層的影響
主機(jī)內(nèi)存100G,對200G 大表?db1. t全表掃描续担,不會(huì)把數(shù)據(jù)庫主機(jī)內(nèi)存用光(分段給客戶端)
mysql -h$host? -P$port -u$user -p$pwd -e "select * from db1.t" > $target_file
InnoDB 數(shù)據(jù)是保存主鍵索引上的擅耽,直接掃描主鍵索引。沒有其他判斷條件物遇,查到每行放到結(jié)果集(服務(wù)端不需保存完整結(jié)果集)乖仇,返回客戶端。
1.1 取询兴、發(fā)數(shù)據(jù)流程
1.? 取一行乃沙,寫net_buffer 中。net_buffer_length 內(nèi)存大小默認(rèn)16k诗舰。
2.? 重復(fù)獲取行警儒,直到 net_buffer 寫滿,調(diào)網(wǎng)絡(luò)接口發(fā)出眶根。
3.? 發(fā)送成功蜀铲,清空 net_buffer繼續(xù)。
4.? 發(fā)送返回 EAGAIN 或WSAEWOULDBLOCK属百,本地網(wǎng)絡(luò)棧(socket send buffer)寫滿记劝,等待重新可寫
1.? 查詢發(fā)送過程中,占用內(nèi)存最大net_buffer_length 族扰,不會(huì)200G厌丑;
2.? socket send buffer 不可能達(dá)到 200G(默認(rèn)定義/proc/sys/net/core/wmem_default),被寫滿渔呵,就暫停讀
1.2?MySQL “邊讀邊發(fā)的”客戶端接收慢怒竿,導(dǎo)致 MySQL 服務(wù)端發(fā)不出去,執(zhí)行時(shí)間長扩氢。
客戶端不讀 socket receive buffer 耕驰,服務(wù)端 show processlist?
“Sending to?client”,服務(wù)器端網(wǎng)絡(luò)棧寫滿类茂。
–quick 參數(shù)耍属,用mysql_use_result 方法托嚣。讀一行處理一行巩检。處理邏輯如果很慢,如圖 2 情況示启。
正常線上業(yè)務(wù)說兢哭,查詢返回不多,mysql_store_result 查詢結(jié)果保存本地內(nèi)存夫嗓。
第 30 篇文章大查詢導(dǎo)致客戶端占用內(nèi)存近 20G迟螺,用mysql_use_result 接口冲秽。“Sending to client”優(yōu)化查詢結(jié)果矩父,并評估這么多的返回結(jié)果是否合理锉桑。
快速減少線程,net_buffer_length設(shè)置更大
1.3 Sending data
Sending to client:等待客戶端接收結(jié)果
Sending data:正在執(zhí)行窍株,如發(fā)送數(shù)據(jù)民轴,查詢,鎖等待
網(wǎng)絡(luò)沒問題球订,為什么 Sending data 要這么久后裸?
查詢執(zhí)行狀態(tài)“Sending data”;發(fā)送執(zhí)行結(jié)果給客戶端冒滩;繼續(xù)微驶,完成設(shè)置成空字符串?
B 等鎖 Sending data:
二、全表掃描對 InnoDB 的影響
2.1?Buffer Pool
在第 2和第 15 篇介紹 WAL 機(jī)制开睡,InnoDB 內(nèi)存保存更新結(jié)果因苹,配合 redo log,避免隨機(jī)寫盤篇恒。
Buffer Pool (BP) 管理內(nèi)存數(shù)據(jù)頁容燕, WAL 里加速更新、查詢
提交時(shí)婚度,磁盤上舊數(shù)據(jù)頁蘸秘,查詢來讀, redo log 不需要馬上應(yīng)用到數(shù)據(jù)頁
因?yàn)椋?b>直接讀內(nèi)存數(shù)據(jù)頁(最新)蝗茁,不需讀磁盤醋虏,速度快。
Buffer Pool加速查詢哮翘,依賴內(nèi)存命中率颈嚼。
2.2 內(nèi)存命中率
show engine innodb status 穩(wěn)定線上系統(tǒng),保證響應(yīng)時(shí)間符合饭寺, 99% 以上阻课。
“Buffer pool hit rate”命中率:99.0%。
需要數(shù)據(jù)頁都直接從內(nèi)存得艰匙,命中率100%(生產(chǎn)上難做到)
2.3?Buffer Pool算法
大小innodb_buffer_pool_size 確定限煞,物理內(nèi)存 60%~80%。小于磁盤常見员凝。
十年前署驻,單機(jī)數(shù)據(jù)量上百個(gè) G,物理內(nèi)存幾個(gè) G;服務(wù)器 128G 甚至更高內(nèi)存旺上,單機(jī)數(shù)據(jù)量卻 T 級別瓶蚂。
淘汰最久未用 (Least Recently Used, LRU) 算法(鏈表實(shí)現(xiàn))
1.? 鏈表頭部 P1,最近被訪問數(shù)據(jù)頁宣吱;
2.? 訪問 P3窃这,P3 最前面;
3.? 訪問數(shù)據(jù)頁不在鏈表中征候,Buffer Pool 申請數(shù)據(jù)頁 Px加頭部钦听。內(nèi)存已經(jīng)滿,清空末尾 Pm 倍奢。
2.4 全表掃描問題:
不能直接使用 LRU 算法:掃描200G 歷史數(shù)據(jù)表朴上,平時(shí)沒有業(yè)務(wù)訪問它。
Buffer Pool 全部淘汰卒煞。正在業(yè)務(wù)服務(wù)庫痪宰,內(nèi)存命中率下降,磁盤壓力增加畔裕,SQL 慢衣撬。改進(jìn):
?5:3 LRU 鏈表分?young(頭 5/8) 和 old?(表尾3/8)。
1.? 訪問數(shù)據(jù)頁 P3扮饶,young 具练,移到鏈表頭部
2.? 淘汰掉數(shù)據(jù)頁 Pm, Px在 LRU_old 處甜无。
3.? old 每次被訪問扛点,都要判斷:超過 1 秒移到頭部;否則不變innodb_old_blocks_time 控制岂丘。默認(rèn)值1000毫秒陵究。
順序掃描,數(shù)據(jù)頁第一次和最后次被訪問奥帘,間隔不超 1 秒铜邮, 一直在old ,很快被淘汰寨蹋。
優(yōu)點(diǎn):用到Buffer Pool松蒜,對 young沒影響,保證 Buffer Pool 命中率已旧。
小結(jié)
查詢結(jié)果秸苗,發(fā)送客戶端過程。
邊算邊發(fā)评姨,大結(jié)果难述,server 端不會(huì)保存完整結(jié)果集萤晴。讀不及時(shí)吐句,堵MySQL 查詢過程胁后,不會(huì)內(nèi)存打爆。
淘汰策略嗦枢,大查詢不會(huì)內(nèi)存暴漲攀芯。冷數(shù)據(jù)全表掃描,對 Buffer Pool 的影響也能可控文虏。
全表掃描耗費(fèi) IO 資源侣诺,高峰期不能直接線上主庫全表掃描。
思考題
客戶端性能問題氧秘,對數(shù)據(jù)庫影響更嚴(yán)重年鸳?怎么優(yōu)化?
問題核心“長事務(wù)”丸相。結(jié)合鎖搔确、MVCC 。
更新占行鎖灭忠,別的語句被鎖住膳算;
讀事務(wù)也有問題,undo log 不能被回收弛作,導(dǎo)致回滾段空間膨脹涕蜂。
評論1
mysql dump對業(yè)務(wù)db做邏輯備份保存客戶端(虛擬機(jī)),磁盤很快滿映琳,導(dǎo)致server端出現(xiàn)sending to client狀態(tài)机隙,db更新頻繁,undo表空間變大萨西,堵塞黍瞧,服務(wù)端磁盤空間不足。
評論2
兩個(gè)客戶端都update:第一個(gè)select * from t for update 遲遲不返回?cái)?shù)據(jù)原杂,server端長期占行鎖印颤,其他更新被鎖定,報(bào)鎖等待超時(shí)錯(cuò)誤.
同一個(gè)事務(wù)穿肄,更新之后要盡快提交年局,不要做沒必要的查詢,尤其是不要執(zhí)行需要返回大量數(shù)據(jù)的查詢咸产;
評論3
“Sending to client”服務(wù)器端網(wǎng)絡(luò)棧寫滿矢否。快速減少 net_buffer_length 設(shè)更大值
net_buffer_length 加再大脑溢, socket send buffer 小僵朗,網(wǎng)絡(luò)棧還寫滿狀態(tài)赖欣?
沒發(fā)完緩存net_buffer中,對執(zhí)行器都是“已經(jīng)寫出去”验庙。
net_buffer_length 改大顶吮,不會(huì)“Sending to client”?