MySQL之查詢性能優化一


只有當查詢優化,索引優化,庫表結構優化齊頭並進時,才能實現mysql高性能。

在嘗試編寫快速的查詢之前,需要清楚一點,真正重要是響應時間。

 

查詢的生命周期

通常來說,查詢的生命周期大致可以按照順序來看:從客戶端->服務器->然后再服務器上進行解析->生成執行計划->執行->並返回結果給客戶端。

其中"執行"可以認為是整個生命周期最重要的階段,這其中包括了大量為了檢索數據到存儲引擎的調用以及調用后的數據處理,包括排序,分組等。

對於一個查詢的全部生命周期,上面列的並不完整。這里我們只是想說:了解查詢的生命周期,清楚查詢的時間消耗情況對於優化查詢有很大的意義。

 

慢查詢基礎:優化數據訪問

  1.是否向數據庫請求了不需要的數據

  2.mysql是否掃描額外的紀錄

    查詢是否掃描了過多的數據。最簡單的衡量查詢開銷三個指標如下:

      響應時間。

      掃描的行數。

      返回的行數。

    沒有哪個指標能夠完美地衡量查詢的開銷,但它們大致反映了mysql在內部執行查詢時需要多少數據,並可以推算出查詢運行的時間。

    這三個指標都會記錄到mysql的慢日志中,所以檢查慢日志記錄是找出掃描行數過多的查詢的好辦法。

    響應時間:

      是兩個部分之和:服務時間和排隊時間。

       服務時間是指數據庫處理這個查詢真正花了多長時間。

       排隊時間是指服務器因為等待某些資源而沒有真正執行查詢的時間。---可能是等io操作完成,也可能是等待行鎖,等等。

    掃描的行數和返回的行數:

      分析查詢時,查看該查詢掃描的行數是非常有幫助的。這在一定程度上能夠說明該查詢找到需要的數據的效率高不高。

    掃描的行數和訪問類型:

      在expain語句中的type列反應了訪問類型。訪問類型有很多種,

      從全表掃描(ALL)到

       索引掃描(index)到

       范圍掃描()到

       唯一索引查詢 到

       常數引用等。這里列的這些,速度由慢到快,掃描的行數也是從小到大。

    如果發現查詢需要掃描大量的數據但只返回少數的行,那么通常可以嘗試下面的技巧去優化它:

      使用索引覆蓋掃描。

      改變庫表結構。例如使用單獨的匯總表。

      重寫這個復雜的查詢。讓mysql優化器能夠以更優化的方式執行這個查詢。

 

一些簡單的重構查詢的方式:

  1.一個復雜查詢 or 多個簡單查詢

    設計查詢的時候一個需要考慮的重要問題是,是否需要將一個復雜的查詢分成多個簡單的查詢。

  2.切分查詢

    有時候對於一個大查詢我們需要“分而治之”,將大查詢切分為小查詢,每個查詢功能完全一樣,只完成一小部分,每次

    只返回一小部分查詢結果。

  3.分解關聯查詢

    select * from tag 

       join tag_post on tag_post.tag_id = tag.id

       join post on tag_post.post_id = post.id

    where tag.tag = 'mysql'

    可以分解成下面這些查詢來代替:

    > select * from tag where tag = 'mysql'

    > select * from tag_post where tag_id = 1234

    > select * from post where post_id in (123, 456, 567, 9098, 8904)    

  優勢:

      讓緩存的效率更高。

      將查詢分解后,執行單個查詢可以減少鎖的競爭。

      在應用層做關聯,可以更容易對數據庫進行拆分,更容易做到高性能和可擴展。

      查詢本身效率也可能會有所提升。

      可以減少冗余記錄的查詢,

      更進一步,這樣做相當於在應用中實現了哈希關聯,而不是使用mysql的嵌套循環關聯。

 

查詢主流程:

  當希望mysql能夠以更高的性能運行查詢時,最好的辦法就是農清楚mysql是如何優化和查詢的。

  一旦理解這一點,很多查詢優化工作實現上就是遵循一些原則讓優化器能夠按照預想的合理的方式運行。

  

1.客戶端發送一條查詢給服務器

2.服務器先檢查查詢緩存,如果命中了緩存,則立刻返回存儲在緩存中的結果,否則進入下一階段。

3.服務器進行SQL解析,預處理,再由優化器生成對應的執行計划,

4.mysql根據優化器生成的執行計划,調用存儲引擎的API來執行查詢。

5.將結果返回給客戶端。

 

MySQL連接狀態:

對於一個MYSQL連接,或者說一個線程,任何時刻都有一個狀態,該狀態表示了mysql正在做什么,有很多方式能查看當前
狀態,最簡單的是使用show full processlist
在一個查詢的周期中,狀態可能會變化很多次,
這些狀態有:
  sleep:
  線程正在等待客戶端發送新的請求。

  query:
  線程正在執行查詢或者正在將結果發送給客戶端。

  locked:
  在mysql服務器層,該線程正在等待表鎖。在存儲引擎級別實現的鎖,
  例如innoDB的行鎖,並不會體現在線程狀態中。對於myisam來說這是個比較典型的狀態,但在其他沒有
  行鎖的引擎也經常會出現。

  analyzing and statistics:
  線程正在收集存儲引擎的統計信息,並生成查詢的執行計划。

  copying to tmp table [on disk]:
  線程正在執行查詢,並且將結果集復制到一個臨時表,
  這種狀態一般要么是在做 group by 操作,要么是文件排序操作,或者是union操作
  如果這個狀態后面還有 on disk 標記,那表示mysql正在將一個內存臨時表放到磁盤上。

  sorting result:
  線程正在對結果集進行排序

  sending data:
  這表示多種情況,線程可能在多個狀態之間傳送數據,或者在生成結果集,或者在客戶端發送請求。

 

 

總結:

  本文主要介紹了一些關於mysql的查詢流程和一些基本術語,這些對理解mysql優化查詢會有相當大的幫助。

  

 

 


免責聲明!

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



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