在日常開發中,程式設計師寫的最多的除了bug之外,應該算是sql語句了。sql的質量影響了程式的響應速度,只有利用mysql的特性,才能讓mysql更有效的執行查詢sql,充分發揮mysql的優勢,並避開它的弱點。
為什麼查詢速度會慢?
在編寫sql之前,需要清楚一點 -- 真正重要的是響應時間。
如果我們把查詢看作是乙個任務,那麼它由一系列子任務組成,每個子任務都會消耗一定的時間。如果要優化查詢,就是要優化其子任務,要麼消除其中的一些子任務,要麼減少子任務的執行次數。
慢查詢
通過開啟mysql中的慢查詢,可以明確的掌握系統中有哪些sql查詢在影響整個系統的效能,從而更準確的去針對這些sql進行優化。
查詢慢查詢開啟狀態--on/off
show variables like 'slow_query%';
開啟慢查詢日誌
set global slow_query_log='on';
show variables like 'long_query_time';
設定查詢超時(10s)記錄
set global long_query_time=10;
查詢效能低,最基本的原因是訪問的資料太多。某些查詢可能不可避免的需要篩選大量資料,但大部分效能低下的查詢都可以通過減少訪問的資料量的方式進行優化。
使用limit對查詢資料進行限制
開發者通常會誤以為mysql只會返回需要的資料(例如select 取出100條記錄,只在頁面顯示前20條記錄),實際上mysql卻是先返回全部結果集後再進行計算。最簡單有效的解決方法就是在查詢後面加上limit。
多表關聯查詢只取需要的列
例:查詢所有在電影《七宗罪》中的演員
select * from actor inner join filmactor using(actorid) inner join film using(film_id) where
film.title='se7en';
上述sql將返回這三個表的全部資料列。正確的開啟方式應該如下只取需要的列:
select actor.* from actor...
看到select *的時候都需要用懷疑的眼光審視select *會取出全部列,這樣會讓優化器無法完成索引覆蓋掃瞄這列優化,還會為伺服器帶來額外的i/o、記憶體和cpu的消耗。因此專案組都會嚴格禁止select *的寫法。
合理使用快取
當程式出現不斷重複執行相同的查詢sql,然後每次返回的結果都一樣的情況,作為一名合格的程式設計師,你應該考慮到將初次查詢的結果集快取起來。如果查詢快取是開啟的,mysql會優先檢查這個查詢是否命中快取中的資料。這個檢查是通乙個對大小寫敏感的雜湊查詢實現的。查詢和快取中的查詢即使只有乙個位元組不同,那也不會匹配快取結果。若當前的查詢恰好命中快取且使用者許可權沒有問題,那麼mysql會跳過所有其他階段,直接衝快取中拿到結果並返回給客戶端。
查詢優化器
經過mysql優化器選擇的執行計畫並不一定是最快的執行方式。
下面是一些mysql能夠處理的優化型別:
優化count(),min()和 max():
覆蓋索引掃瞄:
提前終止查詢
列表in()的比較:
執行計畫:mysql 效能優化神器 explain 使用分析
高效利用索引
索引的最左字首匹配:
使用使用者自定義變數
使用者自定義變數是乙個很容易被忽略的mysql特性,但是如果能夠用好,發揮其潛力在某些場景下可以寫出非常高效的查詢語句
使用者自定義變數是乙個用來儲存內容的臨時容器,可使用set和select語句來定義:
set @one:=1;
set @min_actor:=(select min(actor_id) from actor);
set @last_week:=current_date - interval 1 week;
可以在任意可以使用表示式的地方使用自定義變數.
select ... where col <= @last_week;
一下場景不能使用使用者自定義變數:
使用自定義變數示例:
#實現對電影演員演出場次的排名
#只有當前演員參演的電影數量和前乙個演員不同時排名才會發生變化
#使用三個變數分別儲存當前的排名,前乙個演員的排名,當前演員參演的電影數量
set @curr_cnt := 0,@prev_cnt := 0,@rank :=0;
select actor_id,
@curr_cnt := cnt as cnt,
@rank := if(@prev_cnt <> @curr_cnt,@rank + 1,@rank) as rank,
@prev_cnt := @curr_cnt as dummy
from (
select actor_id,count(*) as cnt
from film_actor
group by actor_id
order by cnt desc
limit 10
) as der;
mysql in語句優化
mysql會對sql語句做優化,in 後面的條件不超過一定數量仍然會使用索引。mysql 會根據索引長度和in後面條件數量判斷是否使用索引。另外,如果是in後面是子查詢,則不會使用索引。乙個文章庫,裡面有兩個表 category和article。category裡面有10條分類資料。article裡...
MySQL IN 查詢優化
前幾天看到一篇博文將 in 子查詢 優化為 left join 的問題,今天自己測試測試。資料表為 test item 和 test item tag 兩個表 test item 兩個字段 item id char 36 release time int 11 共10w條記錄 test item t...
mysql in語句優化
mysql會對sql語句做優化,in 後面的條件不超過一定數量仍然會使用索引。mysql 會根據索引長度和in後面條件數量判斷是否使用索引。另外,如果是in後面是子查詢,則不會使用索引。乙個文章庫,裡面有兩個表 category和article。category裡面有10條分類資料。article裡...