MySQL 優化實例--查詢優化 索引優化 邏輯優化

優化實例:1 查找與用戶同一地區性別爲女的信息,按照最後登錄時間排序

前提是:數據庫有百萬數據,而且用戶訪問很頻繁

查詢SQL:select * from user where area = '$area' and sex = '$sex' order by lastlogin desc limit 0 ,30;

需要注意的是,數據庫中有百萬條數據,但這裏只要求檢索出30條數據就可以

如果單純的只在area上建立索引,首先會檢索出所有area匹配的數據(因爲建了索引,所以這是很快的),但是其他的字段沒有建立索引,所以還要在命中sex,仍然會檢索地區是$area的數據量。如果建立了area和sex的複合索引,效果略好,但仍然會檢索area = '$area' and sex = '$sex',然後排序。如果建立了area sex 和lastlogin的複合索引,該索引基於area sex和lastlogin的三個字段合併排序,很輕鬆的就能將數據檢索處理,而且只需要檢索出30條數據,無需檢索百萬數據。

認識影響結果集,影響結果集是檢索數據所檢索的行數,輸出結果集是真正返回的行數,對我們起真正決定意義的還是影響結果集。

影響結果集的範例:

查詢語句:select users from user where area = '北京' and sex = '女'

假設索引爲area,假設所有的用戶共有1000000人,北京的用戶有100000人,那影響結果集就是100000人。而不是1000000,這樣的話對於性能有一定的好處,但10w也不是個小數目,北京的女性用戶有50000人,這樣因爲索引是area所以,影響結果集是100000,而返回結果集是50000.如果沒有索引的話,影響結果集就是1000000,輸出結果集是50000,這是多麼可怕的事情啊,要檢索1000000條數據,這在數據庫中基本上市不可能存在的事情我覺得,因爲但凡有這麼多是數據量,一定會有專門的DBA來維護,DBA是不允許這種事情發生的。如果對area 和sex做複合索引呢?那影響結果集就是50000,輸出結果集還是50000.效率很高,雖然檢索了50000條數據,但這是用戶確切需要的,其他優化還在繼續,而索引能做的,就這麼多了。在擴展一下,如果在sql後面加一個limit 0,30;很明顯輸出結果集就是30條數據,而當我們對area和sex進行索引的時候,以爲索引已經是排序過的,索引只需要檢索出30條數據來就可以了,非常方便。但是如果我麼在Limit前面加上order by lastlogin的話呢?很明顯之前沒有對Lastlogin建索引,所以影響結果集是50000而輸出結果集還是30,這是非常浪費資源的,所以解決辦法就是對area sex 和lastlogin建立複合索引。

優化實例:2  毫秒級優化案例

遊戲用戶登錄後臺,顯示最新賬戶信息。

查詢爲: select *  from user where uid = $uid order by timeline desc limit 20;

這是高頻操作,每天有數百萬次次執行,出現的問題:因爲該搜索每執行一次的影響結果集是幾百至幾千條數據,在上千條結果集的情況下,該sql查詢開銷通常在0.01秒左右,建立uid+timeline複合索引,將排序引入到索引結構中,影響結果集就變成了20,每條sql查詢的開銷變成了0.001,數據庫負載驟降。

優化實例:3 Innodb鎖表案例

某遊戲數據庫的存儲引擎是innodb,innodb是行表鎖,理論上來說很少存在鎖表情況。有一條語句,

delete grom username where uid = $uid

該語句執行的很少,每天大約只執行10次,20次左右,但這個數據庫表容量百萬級,而且悲催的是這個uid未建立索引,於是更悲催的事發生了,由於未建立索引,每次執行該操作的時候,delete遍歷全表,全表被delete鎖定,由於百萬條記錄遍歷時間過長,期間大量select被阻塞,導致數據庫連接崩潰。

優化實例:4  論壇翻頁優化

select * from post where tagid = '$tagid' order by lastpost limit $start,$end;

如果是超級熱帖,幾萬個回帖,用戶頻繁翻頁,limit 25700,100,那將是很可怕的事。

我的思路:首先肯定是要建索引,tagid和lastpost的複合索引,但翻到末頁的時候也會有很大的影響結果集,很明顯單純的使用索引優化是不夠 ,我們可以從兩方面來優化。一:改變sql語句,目的是減少影響結果集,這種方法也是我借鑑的別人的,自己完全沒有思路。獲得當前頁的最大值$maxlast和最小值$minlast,然後將sql語句修改爲:select * from post where lastpost >$minlast and lastpost < $maxlast;這樣

影響結果集就變成了$end,效率獲得了極大的提升。而且這種情況不適合建立靜態頁面或者見緩存,因爲是實時更新的。

 Mysql執行狀態監控

show processlist

執行狀態分析:

    sleep 連接過多導致,資源未釋放,表示數據庫一直運行,數據庫未斷開。

  locked 更新操作鎖定,更新表示可能是插入 修改 和刪除,通常使用INNODB可以很好的減少表鎖,在myisam中locked是很多高併發  應 用的噩夢,所以官方也開始推薦使用INNODB;

  其他的不做介紹了,太多了,不會經常見到的

    sendingdata sql語句優化的不夠好,通常是影響結果集太大
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章