在公司后台某模块功能记录日志中有一个搜索功能,经过前段时间的产品使用时间区间进行搜索反馈有些卡顿,我发现这个搜索功能比较慢,要3秒左右才能出来,就决定对这里作一下优化。mysql
经过分析代码和SQL发现最核心的问题在于一个区间查询耗时太长,耗时2秒多,因此我决定看看这里能不能优化,其中核心SQL为sql
SELECT * FROM XXX_log WHERE (`ctime` BETWEEN '2017-09-11 09:34:13' AND '2017-10-11 09:34:13') and id > 27851 AND column1 = 'xxx' AND (column2 = 'null' OR LENGTH(column2) > 91) ORDER BY id DESC LIMIT 0, 30
这个查询是一个简单查询,没有联表,就是单表的limit分页查询,外加一个时间区间和字段搜索,我经过SQL分析 explain 发现并未走索引,扫描区间也很大,因为该表拥有接近100万的记录,查询的扫描区间接近50万,我感受这样确定是效率不高的。运维
而后查询了一下数据,发现耗时确实在2.6秒左右,我起初的设想是,column2字段查询确定是无法改了 ,毕竟那涉及到之前的业务,该字段这样搜索查询确实有违常理,可是既然以前的功能已经这样设计了,如今去作调整,反而有可能有问题,那么就只有在 id ctime column1下手了,id它写死了,定了某条记录开始进行查询,我猜想可能以前的数据是测试数据或者是废弃数据,那既然有个标尺,就不去动它,column1是固定的查询值,这样也无法改,这样的固定值在数据行中差别不明显,加索引效果也不大,而后是ctime了,惟一能动文章的也只有它了。测试
而后我好好分析了一下这个模块要实现的功能逻辑,就是查询这段时间内符合要求的数据,这段时间,很明显是一个月,能不能设定这个查询区间只能查一个星期呢?优化
我改成一周内的时间区间查询,确定能下降查询的查询区间啊,然而使人遗憾的是,这个下降查询区间间隔,并无多大效果,最后无奈,我给ctime添加了一个 normal index btree索引,加了索引后,我本觉得一切都会好起来,谁知,explain后效果仍是那样!spa
可能用到的索引keys 主键 ctime ,然而呢 查询区间仍是接近45万,效果并不明显,查询时间也仍是2秒多,这可以让我犯难了,一时一筹莫展,思考许久,忽然想到这感受是索引没有真正生效致使的,那么能不能强制告诉mysql使用某个索引了,让他主动是走某个索引,而后我查询了资料 找到了force index(强制要走的那个索引) ,我立刻就试了一下设计
SELECT * FROM XXX_log force index(ctime) WHERE (`ctime` BETWEEN '2017-09-11 09:34:13' AND '2017-10-11 09:34:13') and id > 27851 AND column1 = 'xxx' AND (column2 = 'null' OR LENGTH(column2) > 91) ORDER BY id DESC LIMIT 0, 30
果真 explain分析以后 使用了ctime索引日志
并且查询区间下降到3万多了,这个效果太明显了,耗时下降到0.2秒左右,而后这个功能立刻从3秒才能打开下降到0.3秒就能打开了,这个优化效果令我很是满意。code
在和运维讨论该表的数据时,运维提供方案说,看到该表数据量庞大 接近100万,而且时间不少是2015年 2016年的,他提出能够转移2015年 2016年的数据,我查看了一下,2015年和2016年的数据合计起来有70多万了,占据了绝大部分,若是转移的话,确实有利于咱们查询啊,比对啊,更新啊之类的,由于这是一张日志表,在某个期间具备时效性,毕竟大部分时候今年不会再看去年前年的查询数据了,因此我以为这种作法也有依据,也合理,恰逢同事请假休息,此事等他回来再作讨论。orm
本次想到强制使用索引,也是灵光一现,稍微有一些运气在里面的,否则还真很差解决这个问题,算是天公做美吧!遂感慨一首:
苍茫青天显神威,
拦路崔嵬面如灰。
忽而得来灵光现,
开山破土镇边陲!