1.案例in查询条件很慢
其中in中共115个
select
id,detail_id,request,response,utime,ctime
from response_detaill
where detaill_id in
(26371986, 26372242, 26371984, 26371990, 26400150, 26371988, 26371994, 26371992,26371998, 26371996, 26371970, 26371968, 26371974, 26400390, 26371972, 26371978,26371976, 26371982, 26371980, 26400178, 26372018, 26400435, 26372016, 26402486,
26372022, 26372534, 26372020, 26372026, 26372024, 26372030, 26404286, 26404287,
26372028, 26404285, 26372002, 26400163, 26400160, 26372000, 26372006, 26372004,
26400165, 26372010, 26372008, 26372014, 26372012, 26372050, 26372048, 26404290,
26404291, 26404288, 26404289, 26404294, 26404292, 26404293, 26372042, 26400201,
26372044, 26372338, 26372082, 26372346, 26468863, 26372064, 26372836, 26372068,
26400235, 26402028, 26400018, 26400019, 26400022, 26400020, 26400024, 26372892,
26372124, 26372098, 26372864, 26400011, 26400520, 26400012, 26372402, 26400048,
26402356, 26400315, 26468922, 26400056, 26372926, 26400063, 26372668, 26372156,
26372128, 26400042, 26400046, 26372142, 26400594, 26372434, 26402129, 26400593,
26400071, 26400586, 26372426, 26400335, 26400588, 26371954, 26371952, 26371958,
26371956, 26371962, 26371960, 26371966, 26371964, 26402401, 26372708, 26371946,
26371944, 26371950, 26371948)
慢查询监控平台:
查看该sql语句的执行计划,type:range指的是有范围的索引扫描,相对于index的全索引扫描,它有范围限制,因此要优于index。关于range比较容易理解,出现了range,则一定是基于索引的。
分析原因:
执行计划中显示,是使用了索引,所以不是索引失效的问题
回表次数增加:如果 IN
列表中的值很多,即使使用了索引,也需要进行大量的回表操作,会导致查询变慢,需要的字段是大文本,无法建立索引,使用覆盖索引优化。
网络传输:100M的数据量,增加了传输耗时
内存缓冲限制:Mysql中一页数据是16KB,每条数据需要多个分页数据,增加了磁盘IO
综合来看,是数据量太大导致,考虑只查询需要的字段,不用返回所有的字段,减少数据量。
修改:
select
id,detail_id,response,ctime
from response_detaill
where detaill_id in
(26371986, 26372242, 26371984, 26371990, 26400150, 26371988, 26371994, 26371992,26371998, 26371996, 26371970, 26371968, 26371974, 26400390, 26371972, 26371978,26371976, 26371982, 26371980, 26400178, 26372018, 26400435, 26372016, 26402486,
26372022, 26372534, 26372020, 26372026, 26372024, 26372030, 26404286, 26404287,
26372028, 26404285, 26372002, 26400163, 26400160, 26372000, 26372006, 26372004,
26400165, 26372010, 26372008, 26372014, 26372012, 26372050, 26372048, 26404290,
26404291, 26404288, 26404289, 26404294, 26404292, 26404293, 26372042, 26400201,
26372044, 26372338, 26372082, 26372346, 26468863, 26372064, 26372836, 26372068,
26400235, 26402028, 26400018, 26400019, 26400022, 26400020, 26400024, 26372892,
26372124, 26372098, 26372864, 26400011, 26400520, 26400012, 26372402, 26400048,
26402356, 26400315, 26468922, 26400056, 26372926, 26400063, 26372668, 26372156,
26372128, 26400042, 26400046, 26372142, 26400594, 26372434, 26402129, 26400593,
26400071, 26400586, 26372426, 26400335, 26400588, 26371954, 26371952, 26371958,
26371956, 26371962, 26371960, 26371966, 26371964, 26402401, 26372708, 26371946,
26371944, 26371950, 26371948)
修改之后查询时间变为100ms,由原来的1s变为100ms,由此可见,是因为数据太大导致网络延时与Mysql的内存限制
还可以修改为连表查询join
2. 分页查询很慢
背景:负责的项目中慢查询数量报警,通过数据库分析诊断平台可以看出有一条sql命令慢查询数量超过阈值,是一个分页查询,需要查询某个范围内的数据,使用limit,深度分页导致慢查询。
select * from flow where group_id=3290 limit 150000,100;
分析:这条查询语句一直都没有问题,最近突然有问题,发现最近几次使用的数据集合都是很大的,导致每次分页limit偏移量较大,平均查询时间>2s。explain分析执行计划,使用了非唯一索引。即使有索引,索引只能加速定位,但无法直接“跳转到第 N 条”(因为索引存储的是键值,而不是行号)。
解决:采用游标分页,将查询上一页的最大id返回,下一页的查询基于此id
select * from flow where group_id=3290 AND id>150000 limit 100;
深度分页的本质:
LIMIT offset, size 的工作原理:
数据库会先读取 offset + size 条数据,再丢弃前 offset 条。
第一条查询实际加载了 5000600 行数据,再丢弃前 5000000 行。