數據庫查詢慢的緣由

前言

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

本文內容參考自公衆號文章:mysql

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

我對公衆號中的內容做本身的梳理總結sql

開始數據庫

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

對於第一種狀況,可能查詢語句自己沒有問題,是數據庫遇到了其餘問題;函數

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

偶爾效率慢的狀況

緣由一:刷新「髒」頁

什麼是「髒」頁

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

針對這種內存中的數據頁和磁盤上的數據不一樣的狀況咱們將內存中的數據頁稱爲「髒」頁,而內存中和磁盤上數據相同的狀況則稱爲「乾淨」頁。3d

刷新「髒」頁時,系統會暫停其餘的操做,全身心的將數據存到磁盤中,就會致使日常正常執行的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優化一之查詢優化

相關文章
相關標籤/搜索