MySQL的SQL性能優化總結

不少時候,咱們的程序出現的「性能問題」,實際上是咱們本身寫的那"坨"代碼的問題,是本身Coding的問題,是Mysql的DML語句使用的問題。 如下是我總結的關於MySQL DML語句的使用中須要注意的點。mysql

對於select *要時刻保持謹慎的態度

絕大多數狀況,是不須要select *的。一旦使用了這種語句,便會讓優化器沒法完成索引覆蓋掃描這類優化,並且還會增長額外的I/O、內存和CPU的消耗。 固然,使用select *也並非全是壞處,合理的使用select *能夠簡化開發,提升相同代碼的複用性。git

是否掃描的太多額外的記錄

有時候會發現某些查詢可能須要讀取幾千行數據,可是僅返回幾條或者不多的結果,可使用如下方式去優化:github

  • 看看可否改表結構。例如使用匯總表
  • 看看獲取數據結果的方式是否最優,獲取路勁是否已是最短。
  • 使用覆蓋索引,把全部須要的列都放到索引中,以減小返回表中對應行中取數據的步驟。

切分某些SQL語句

傳統的互聯網系統中,強調網絡鏈接儘可能少,數據層儘量在一次鏈接中完成儘量多的工做,防止創建屢次連接,可是這種想法對於MySQL並不適用,MySQL從設計上讓鏈接和斷開都很輕量,在通常服務器上能夠支持每秒超過10萬的查詢。redis

因此對於有些場景下,能夠將一個大的查詢「分而治之」,切分紅小查詢,而後再組合起來。例如如下狀況:sql

  • 對於全量數據查詢變成分頁。假如一張表中有數千萬條數據,一次select all,確定是不行的。能夠換成一次取一部分,把一次的壓力分攤。
  • 刪除大量舊數據的時候,不要一個大的語句一次性清完,推薦一次刪一萬條。若是用一個大的語句一次性完成的話,可能須要一次鎖住大量數據,佔滿大量日誌事務,讓Mysql停在那兒了,爲避免這種狀況發生,最好一次性刪除一萬條左右的數據,而後每次刪完暫停一下子再操做,將服務器上的一次性壓力分散。

注意:雖然Mysql創建鏈接十分輕量,可是這不意味着能夠逐條循環中查詢而後再拼接,這樣效率依然是很是慢,並且一般是工做中sql優化的點。數據庫

慎用join操做

這算是一條禁忌吧,不少公司的互聯網產品都杜絕join操做,換成先從一張表中先取出數據id,再從另一張表中使用where in查詢的兩次單表查詢操做。主要是如下幾點緣由:緩存

  • 讓應用的緩存(redis、memcache等)更高效。例如在第一張表中查詢出部分id了,若是命中了緩存,就能夠省去一條where in語句了。
  • 更容易應對業務的發展,方便對數據庫進行拆分,更容易作到高性能和高擴展。
  • 對where in中的id進行升序排序後,查詢效率比join的隨機關聯更高效
  • 減小多餘的查詢。在應用層中兩次查詢,意味着對某條記錄應用只須要查詢一次,而使用join可能須要重複的掃描訪問一部分數據。
  • 單張表查詢能夠減小鎖的競爭。

假如非用不可,能夠採用如下方式來優化:服務器

  • 確保ON或者using子句中的列上有索引
  • 確保任何的group byorder by中的表達式只涉及到一個表中的列。

在性能要求比較高的場景中,杜絕查詢中使用臨時表

MySQL的臨時表示沒有任何索引的,使用臨時表通常都意味着性能比較低,所以在對性能要求比較高的場景中,最好不要使用帶有臨時表的操做:微信

  • 未帶索引的字段上的group by操做。
  • UNION查詢。
  • 查詢語句中的子查詢。
  • 部分order by操做,例如distinct函數和order by一塊兒使用且distinctorder by同一個字段。再例如某些狀況下group byorder by字段不一樣。

具體是否用到臨時表,能夠經過explain來查看,查看Extra列的結果,若是出現Using temporary則須要注意。markdown

count()函數優化

count()函數有一點須要特別注意:它是不統計值爲NULL的字段的!因此:不能指定查詢結果的某一列,來統計結果行數。即count(xx column) 不太好。

若是想要統計結果集,就使用count(*),性能也會很好。

儘可能不使用子查詢

儘可能別使用子查詢,儘量的使用關聯來代替

優化分頁limit

一般咱們在分頁的時候,一般使用的是limit 50, 10這種語句。數據少還不錯,可是當數據偏移量很是大的時候,性能就會出現問題,例如select xx,xxx from test_table limit 100000020, 20。掃描了100000020條數據,才返回20條數據。這個時候咱們能夠用一下兩種方式來優化:

利用between and和主鍵索引

利用主鍵自增id,咱們若是知道了分頁的上邊界,以上查詢能夠改寫爲: select xxx, xxx from test_table where id between xxxxx and xxxx

利用自增主鍵索引、order bylimit,不使用offset

limitoffset的問題,其實就是offset的問題,它會致使MySQL掃描大量不須要的行而後再拋棄掉。若是使用某個標籤記錄上一次所取數據的位置,那麼下次就能夠直接從書籤位置開始掃描,這樣就能夠避免使用offset

例如以上查詢能夠改成:

第一組數據:``select xxx, xxxx from test_table order by id desc limit 20;

這樣就拿到了本次數據和下次數據的分解id值,則下一頁查詢就知道能夠: select xxx, xxx from test_table where id < '上頁id分界值' order by id desc limit 20

熟悉並靈活使用explain

如下是mysql執行查詢的整個過程,explain能夠查看圖中標紅部分,

explain會展現不少字段和內容,其中的內容每每很差記,使用的時候,能夠查看如下圖解內容: explain圖解

更多精彩內容,請關注個人微信公衆號 互聯網技術窩 或者加微信共同探討交流:

相關文章
相關標籤/搜索