現象:列表頁因超時查不出來東西,使用postman模擬請花費40多秒,將sql語句單獨提出來后查詢速度非常慢,40多秒
先上結論:
在兩個表關聯字段上建立索引解決此問題,下面的內容比這句話爽多了,請繼續看
表結構如下:
users(用戶)表:id,name
integal_record(分數記錄)表:id,user_id,integal_id
其中,integal_record表的user_id關聯着users表的id,業務目的是查詢每個員工閱讀次數、評論次數和積分總和,查詢語句如下:
(里面寫死的值是我從mybatis里扣出來的)
integral_id=1代表着閱讀,integral_id=2代表着評論
SELECT u.`name` , IF(SUM(ir.integral_id = 1) > 0, SUM(ir.integral_id = 1), 0) AS 'read' , IF(SUM(ir.integral_id = 2) > 0, SUM(ir.integral_id = 2), 0) AS 'comment' , IF(SUM(ir.integral_id = 1) > 0, SUM(ir.integral_id = 1), 0) + IF(SUM(ir.integral_id = 2) > 0, SUM(ir.integral_id = 2), 0) AS count FROM users u LEFT JOIN integral_record ir ON ir.user_id = u.id WHERE u.role_code = 1 AND u.actived = 1 AND u.deleted_at > now() AND u.network_id = 29 AND u.id NOT IN ( SELECT user_id FROM roles WHERE role_item_id = 7 ) GROUP BY u.id ORDER BY ifnull(SUM(ir.integral_id = 1), 0) + ifnull(SUM(ir.integral_id = 2), 0) DESC, u.pinyin ASC;
共11644條 查詢時間:27.976s
查詢時間快半分鍾是無法讓人接受的,從表象的SQL語句來說,首先我們看到有很多SUM函數,因此我們來測試下SUM函數的計算時間,如下查詢每個人閱讀的累計次數:
select SUM(integral_id=1) as 'count' from integral_record group by user_id;
共13000條 查詢時間:0.084s
可以看出來計算時間很長和SUM函數沒什么關系,再看整個SQL除了一些SUM函數外就剩下users表左聯integal_record表,我們把條件去掉,直接就寫個左查詢試試
select * from users u LEFT JOIN integral_record mtemp on u.id =mtemp.user_id;
共13001條 查詢時間:69.919s
amazing,我的users表里有13400條數據,關聯的integral_record 表里也有13000條數據,僅僅做了左連接竟然花費了70秒,這肯定是超時的元凶;所以我們explain一下,看看mysql對這條數據的查詢策略:
EXPLAIN select * from users u LEFT JOIN integral_record mtemp on u.id =mtemp.user_id;
查看結果:

我們看到type字段的結果是All,也就是代表全表掃描,那么就好辦了,建立索引即可,其中users表中的id屬於主鍵,策略自增,有默認的索引,不在考慮范圍內,我們僅需對integral_record表增加索引即可:
alter table integral_record add index user_id_index(user_id)
繼續執行左聯語句查看運行時間:
select * from users u LEFT JOIN integral_record mtemp on u.id =mtemp.user_id;
共13406條 查詢時間:67.549s
時間仍然很久,索引並沒有起作用,這里排除一些逃避困難時的迷信想法:mysql有bug 或者navicat有bug,有網絡問題 哈哈哈.....我們來看左聯的關鍵屬性:

user_id竟然是varchar的 ,但是users表中的id是int,這就造成了left join on users.id =integral_record.user_id時有類型轉換的問題而不能使用索引,因此,我們把user_id更改成int,再看看時間....(盡管兩三句就寫完了,這個數據類型煩擾了我整整找了一上午去找)
select * from users u LEFT JOIN integral_record mtemp on u.id =mtemp.user_id;
共13406條 查詢時間:0.375s
執行時間從60多秒變成了0.375s,整個世界都安靜了,再次explain一下
EXPLAIN select * from users u LEFT JOIN integral_record mtemp on u.id =mtemp.user_id;

發現mtemp(integal)表的檢索方式從all變成了ref,索引,快的一批,深呼吸....
鏈接:https://www.jianshu.com/p/096977d33441
來源:簡書