查詢大量資料速度很慢_為什麼查詢資料不多,卻慢的離譜,在我請教了隔壁新來的阿里大佬後...
技術標籤:查詢大量資料速度很慢
這篇文章主要記錄,造成查詢數量不大的情況下,造成查詢緩慢的原因,以及相應的解決方法。
環境說明:
MySQL 版本 5.7.27
隔離級別:RR
鎖等待造成查詢速度很慢
MDL 鎖
如開啟如下事務:
Session A 持有表 t MDL 寫鎖。Session B 需要 MDL 讀鎖。這時讀寫鎖互斥,Session B 被阻塞。
flush 阻塞
flush 操作一般來說很快就能執行完,當通過查詢程序狀態後,看到被 flush 操作被阻塞,一般都是由其他語句引起的。
如下面事務:
Session A 在掃描每一行時會休眠1s,而 Session B 的 flush tables t; 需要關閉表 t,要等 Session A 結束。後面的 Session C 被 Session B 阻塞了。
flush 的操作示範:
# flush 表 tflush tables t with read lock;# flush 所有表flush tables with read lock;flush 的作用在 全域性鎖 文章中已經介紹過,FTWRL 主要用於 MyISAM 這樣不支援事務的引擎,保證在備份時檢視資料一致性。
行鎖
這裡的行鎖,用兩階段鎖來體現。其他如間歇鎖和 next-key 鎖都會可以造成這樣的現象。
Session A 擁有 id=1 這行的寫鎖,Session B 想要擁有這一行的讀鎖,讀寫鎖互斥。
解決方法
首先通過 show processlist; 命令查詢被阻塞的狀態資訊。如需進一步分析的話,可以將 performance_schema=on 開啟,通過查詢 select blocking_pid from sys.schema_table_lock_waits; 具體造成鎖等待的原因。然後 kill掉相應的 session.
在開啟 performance_schema 會有一定的效能損失。
查詢確實慢
沒有設定合適的索引
如果沒有設定合適的索引,導致掃描行數過多,時間自然就慢了。對於這種情況,可以開啟慢查詢日誌,檢視語句的執行過程,然後進行分析。
預設情況,慢查詢日誌時關閉的,開啟方式如下:
# 查詢慢查詢日誌狀態及儲存位置# show variables like '%slow_query_log%';# 查詢慢查詢日誌的設定時間show variables like '%long_query%';# 臨時開啟慢查詢日誌,MySQL 重啟後失效set global slow_query_log=1;# 改變時間set long_query_time=0;
事務隔離的影響
在事務究竟有沒有被隔離這篇中,我們知道表中的每行資料都有多個版本,在一致性檢視開啟後,檢視的一致性讀的結果就是通過和資料行的版本比較進而顯示的結果。
這時第一個 select 語句就會比第二個加鎖的 select 語句還要慢。
因為第一個 select 語句是一致性讀,需要從 100 萬條回滾日誌中比較直到找到適合的版本。
而第二個 select 語句是當前讀,直接讀取最新版本就可以了。所以花費的時間不一樣。
總結
造成查詢小資料量,卻很緩慢的原因一般有兩種,第一種可能是所查資料被鎖住。另一種確實是查詢過程是真的很慢。
對於資料被鎖住的情況,一般會由 MDL 鎖,FLUSH 操作被阻塞,行鎖造成。
對於查詢確實很慢來說,考慮下索引是否設定的合適。並注意在 RR 級別下,是否由於一致性讀和當前讀的不同而造成查詢速度不一致的情況。
在分析原因時,可以通過程序狀態以及 sys.innodb_lock_waits 中的資訊,來做出相應的處理。
推薦閱讀
盤點:2020年最新、最全、最實用的Java崗面試真題,已收錄GitHub
絕對乾貨,掌握這27個知識點,輕鬆拿下80%的技術面試(Java崗)
一線大廠為什麼面試必問分散式?
在一次又一次的失敗中,我總結了這份萬字的《MySQL效能調優筆記》
併發程式設計詳解:十三個工具類,十大設計模式,從理論基礎到案例實戰
如何高效部署分散式訊息佇列?這份《RabbitMQ實戰》絕對可以幫到你