數據庫查詢慢的原因


前言

本文只但從數據庫本身來看查詢慢的可能因素,至於內存不夠、網速較慢不屬於本文討論范疇。

本文內容參考自公眾號文章:

騰訊面試:一條SQL語句執行得很慢的原因有哪些?---不看后悔系列

我對公眾號中的內容作自己的梳理總結

開始

首先要分類討論一下,這條查詢語句是在偶爾的情況下查詢效率慢,還是一直都存在查詢效率慢的問題。

對於第一種情況,可能查詢語句本身沒有問題,是數據庫遇到了其他問題;

對於第二種情況,應該是查詢語句出了問題,需要優化

偶爾效率慢的情況

原因一:刷新“臟”頁

什么是“臟”頁

當對數據庫進行插入或者更新操作時,數據庫會立刻將內存的數據頁上的信息更新,但是不會立刻將將更新的數據存到磁盤上,而是先保存到redo log中,等合適的時機在將redo log的信息存儲到磁盤上

針對這種內存中的數據頁和磁盤上的數據不同的情況我們將內存中的數據頁稱為“臟”頁,而內存中和磁盤上數據相同的情況則稱為“干凈”頁。

刷新“臟”頁時,系統會暫停其他的操作,全身心的將數據存到磁盤中,就會導致平常正常執行的mysql語句變慢

什么時候會刷新“臟”頁

case1:redo log裝滿時

case2:內存不夠用時

case3:mysql認為系統空閑時

case4:mysql正常關閉時

 

原因二:數據被鎖住

可以用show processlist命令查看一下語句執行的狀態,查看要查詢的數據是否被鎖住

 

一直都存在效率慢的情況

原因一:查詢的數據量太大

查看是否查詢了不必要的行與列,避免用select * from table這樣的語句

 

原因二:沒有用到索引

當數據量很大時,若沒有用索引采用全表索引是很耗費時間的。而這里沒有用到索引由可以分多鍾情況

case1:沒有建索引

case2:索引失效

引起索引失效的可能原因

1)在索引列上用了內置函數或者其他+-*/運算

2)用通配符開頭

3)多列索引違背最佳最匹配原則

4)or操作符容器造成索引失效,除非or的每個操作列都有索引

5)字符串不加單引號

case3:系統選錯索引

系統選錯索引其實是索引失效的一種形式,但是由於涉及到的知識點較多,所以單獨拿出來分析。

系統選錯索引導致索引失效時系統將全表掃描與用索引要掃描的行數進行比較,若是覺得運用索引反而要復雜,則系統就會放棄索引采用全表掃描的方式。

 

那么什么時候會出現運用索引反而比全表掃描效率更低的情況呢

首先我們都知道主鍵索引保存的是整行數據,而非主鍵索引保存的是主鍵的值。所以運用非主鍵索引時要先定位到滿足條件的行的主鍵值,在由主鍵值拿到整行數據的信息,要經過兩次索引的過程。

極端情況下,當索引尋找的數據條件全表都滿足時,則此時索引尋找相比於全表掃描反而多了一系列索引過程。

所以系統在判斷是否需要應用索引時會先判斷如果運用索引大致需要掃描多少行,如果系統預測要掃描的行數很多,則系統會選擇放棄索引采取全表掃描的方式。

 

系統如何判斷運用索引需要掃描的行數?這就需要用到索引的區分度。索引的區分度又稱為基數,一個索引上不同的值越多,意味着出現相同數值的索引越少,意味着索引的區分度越高。

區分度越高,則滿足索引查詢條件的數據就越少,則系統預測掃描的函數不多。

那么索引的區分度又是如何得來的呢?

采樣。系統通過采樣的方式來推測索引的區分度。既然是采樣則就會有誤差,如果你想避免這種誤差,不想要系統進行這種它認為的人性化的選擇方式,你可以強制運用索引

select * from t index(a) where c>100 and c<1000;

 

你也可用下面的第一行命令查看索引的基數,如果基數和實際不符合的話你也可用第二行命令讓系統重新采樣計算索引基數

1 show index from t;
2 analyze table t;

 

可以用explain+SQL查詢語句來查看SQL語句的執行過程,查看是否用到了預期索引

explain命令可以參考我的另一篇博文mysql優化一之查詢優化

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM