背景
先是收到系统警告信息数据库连接超过了2600,接着就收到客户反馈系统进不去,大量的数据库报错,‘SQLSTATE[HY000] [2002] Connection timed out:。。。’,第一反应就是数据库被查爆了;
快速解决方案
为了使系统快速恢复正常,于是选择重启数据库,释放掉数据库连接数,再去追踪和分析数据库慢查询日志;重启完数据库系统恢复了正常,但是监控到慢查询还在不断的产生,于是快速定位相关的业务,发现是定时任务产生的,于是暂停掉了该定时任务,数据库再次重启后恢复了正常(第一次重启后又产生了很多慢查询);
分析慢sql
等系统恢复正常后,可以慢慢分析那条最慢的sql了,执行时间是1432秒,贴上这条慢sql:
explain
SELECT
creative_id,
`advertiser_id`,
`subaccount_id`,
create_time,
update_time
FROM
`originly`
WHERE
`advertiser_id` = 2000
AND `subaccount_id` = 63005
AND `creative_type` = 2
ORDER BY
creative_id ASC
LIMIT
1;
咋一看这条语句还limit 1 了居然还会这么慢, 而且这个originly表也不是特别大,大概也就4百多万数据;于是使用explain 工具查看了下索引使用情况:
发现只使用了creative_type索引,前面那个advertiser_id和subaccount_id 并没有索引,目前表的索引情况如下:
PRIMARY KEY (`__ID__`),
UNIQUE KEY `creative_id` (`creative_id`),
KEY `creative_type` (`creative_type`),
KEY `is_template` (`is_template`),
KEY `advertiser_id` (`advertiser_id`,`ad_id`,`creative_type`) USING BTREE,
KEY `unique_creative` (`advertiser_id`,`ad_id`,`creative_name`) USING BTREE,
KEY `create_time` (`create_time`)
由于creative_type 的值也就那么几种,需要筛选的数据量仍然很多,所以即便是有这个索引,对于大表来说作用很小了,于是想单独在advertiser_id 或者 advertiser_id + subaccount_id 建立索引,笔者先是试了下单独在advertiser_id 上建立索引,发现效果不明显(应该是还得在一个大的数据集里面筛选匹配的operator_subaccount_id)于是选择在advertiser_id + subaccount_id建立组合索引,运行效果发现这个查询很快就有了结果:
总结
(1)其实上面这条语句在一开始并不是一个慢查询,主要是随着数据量的增多变成了慢查询,所以在实际开发中我们需要考虑随着数据量的增大,我们写的sql是不是最优的;
(2)通过以上案例得出一个sql优化思路,我们需要在我们的查询条件的字段上加索引,当然加索引会影响到数据库写入的速度,所以我们需要结合业务对一些经常查询的业务场景做分析然后创建合适的索引;
好了,今天就到这里了,希望对小伙伴们有所帮助,后面还有一些关于慢查询的优化;