MySQL调优实践篇
记一次实习MySQL调优
业务需求:热门帖子展示
- 统计该帖子在某段时间内的评论量、浏览量,按评论量、浏览量、帖子创建时间降序排序
三张表:app_invitation
帖子表、app_invitation_comment
帖子评论表、app_invitation_look
帖子浏览记录表
调优步骤
调优背景:之前离职员工开发好的部分,测试时数据量少,未发现响应速度太慢问题,数据量增加,响应速度太慢,需进行优化
-
先查看代码是否需要优化 :
- 不需要对所有查询出来的数据都进行处理,对需要显示的部分进行处理即可
-
sql语句的编写
原sql语句编写冗余,既联表又子查询都是为得到同一信息点
<select id="moreHotList" resultType="AppInvitation" > SELECT count(b.id) count,a.look, (SELECT IFNULL(sum(look),0) from app_invitation_look where create_time BETWEEN #{start} and #{end} and invitation_id = a.id) look2, a.id, a.type,a.tile_category tileCategory, a.tile_specification tileSpecification,a.description, a.uid, a.phone, a.city, a.hot, a.top, a.longitude, a.latitude, a.enterprise,a.machine_trial machineTrial, a.state, a.dev, a.create_time createTime, a.update_time updateTime FROM app_invitation a LEFT JOIN app_invitation_comment b ON a.id = b.invitation_id LEFT JOIN app_invitation_look c on a.id = c.invitation_id where a.dev = 1 AND a.state = 1 AND a.machine_trial = 1 GROUP BY a.id <if test="last != null "> and a.update_time <= #{last} </if> ORDER BY count desc,look2 desc,a.create_time desc </select>
-
通过
explain
查看执行计划,两个表的type是all
- 分别为app_invitation_comment帖子评论表、app_invitation_look帖子浏览记录表
建立invitation_id的索引
- 结果:子查询和联表部分的type 为
ref
- 分别为app_invitation_comment帖子评论表、app_invitation_look帖子浏览记录表
-
帖子表查询的extra列
using temporary、using filesort
-
using temporary,通过网上检索发现可能是由于
innodb_buffer_pool_size
设置过小,而建立了临时表,通过show variable like “%innodb_buffer_pool_size%”发现现有设置为128M,修改为256M -
using filesort在内存中排序,排序字段是利用联表/子查询统计出来的字段,不好建立索引:
(注:以下执行时间是由于笔者是在数据量小的数据库执行只用于展示)
-
通过
set profiling = 1;
执行sql语句,再show profiles
可以查看具体执行时间 -
可以通过show profile for query query_id,query_id,即对应这Query_ID这一列具体的数值,
即
show profile for query 2;
可以查看每个步骤具体花费时间 -
发现排序较花费时间,排序字段是利用子查询出来的字段,不好建立索引;using filesort在内存中排序,其中有两种排序方式,决定排序方式的
sort_buffer_size
参数设置,默认是1MB,为使用单路排序,选择增大参数值 -
其中一个排序字段创建时间,与自增id是正相关,将create_time改为id
-
结合业务需求,数据库会包含逻辑删除的帖子,即实际上并不是所有帖子都要检索,原本是在联表之后通过where语句筛选,笔者改为在join之前先对帖子进行筛选
-
-
-
最终版本:
<select id="moreHotList" resultType="AppInvitation" >
SELECT count(b.id) comment,a.look,
(SELECT IFNULL(sum(look),0) from app_invitation_look where create_time BETWEEN #{start} and #{end} and invitation_id = a.id) look2,
a.id, a.type,a.tile_category tileCategory, a.tile_specification tileSpecification,
a.description, a.uid, a.phone, a.city, a.hot, a.top, a.longitude, a.latitude, a.enterprise,
a.machine_trial machineTrial, a.state, a.dev, a.create_time createTime, a.update_time updateTime
FROM (SELECT * FROM app_invitation where dev = 1 AND state = 1 AND machine_trial = 1
<if test="last != null ">
and update_time <= #{last}
</if>
) a
LEFT JOIN app_invitation_comment b
on a.id = b.invitation_id and b.create_time BETWEEN #{start} and #{end} and b.hidden = 2 and b.machine_trial = 1 and b.dev = 2
GROUP BY a.id
ORDER BY comment desc,look2 desc,a.id desc
</select>
and b.dev = 2
GROUP BY a.id
ORDER BY comment desc,look2 desc,a.id desc
</select>