昨天真是个悲伤的日子,背了来公司的第一个事故。
事故的根本原因是改动了一个查询条件,用了not in,导致无法命中排序索引,因为线上有个租户表数据有400w+,查询缓慢继而引发Mysql连接数撑爆了实例的CPU。
SQL:
SELECT
`clue_csts`.`confirm_status`,
`clue_csts`.`lose_type_id`,
`b_broker_recommend`.`b_broker_recommendId`,
`c`.`cst_name`,
`b_broker_recommend`.`proj_id`,
`b_broker_recommend`.`cst_id`,
`c`.`mobile_tel`,
`b_broker_recommend`.`last_report_time`,
`b_broker_recommend`.`check_date`,
`stage_id`,
`is_delay`,
`c`.`tel2`,
`c`.`tel3`,
`c`.`tel4`,
`c`.`gender`
FROM
`b_broker_recommend`
LEFT JOIN `b_broker_recommend_cst` `c` ON c.b_broker_recommend_cstId = b_broker_recommend.cst_id
LEFT JOIN `clue_csts` ON clue_csts.clue_cst_id = b_broker_recommend.clueId
WHERE
`b_broker_recommend`.`regbroker_id` = '39ec911a-495a-3357-7e18-1a5c9e15279a'
AND b_broker_recommend.stage_id = '2'
AND (
`c`.`mobile_tel` LIKE '%/+//Um9S5ErCikwXE4dXrWnuEg==/+//uuEySqVtmoCnOoPk9aV1fw==/+//GJg0MA+Q+xqQIknWJPJ8Nw==%'
OR `c`.`tel2` LIKE '%/+//Um9S5ErCikwXE4dXrWnuEg==/+//uuEySqVtmoCnOoPk9aV1fw==/+//GJg0MA+Q+xqQIknWJPJ8Nw==%'
OR `c`.`tel3` LIKE '%/+//Um9S5ErCikwXE4dXrWnuEg==/+//uuEySqVtmoCnOoPk9aV1fw==/+//GJg0MA+Q+xqQIknWJPJ8Nw==%'
OR `c`.`tel4` LIKE '%/+//Um9S5ErCikwXE4dXrWnuEg==/+//uuEySqVtmoCnOoPk9aV1fw==/+//GJg0MA+Q+xqQIknWJPJ8Nw==%'
OR `c`.`cst_name` LIKE '%13858616853%'
)
AND `b_broker_recommend`.`b_broker_recommendId` NOT IN (
'39ec911d-1d24-6c6b-19cf-d4f90c34ec79',
'39ed2864-8169-cec1-0391-51d8681500ec',
'39ed7559-3889-6b8a-a977-835902f4dbbc',
'39ede0e4-6baf-4e6e-11b8-789c285a8b0c',
'39ede123-d7ab-6591-6a36-70791bf62a78',
'39ee24b3-71f6-e4d1-a5b1-7bbfd16cd1de'
)
ORDER BY `b_broker_recommend`.`check_date` DESC
LIMIT 20;
部分表名、字段名已被我替换掉。
索引是:
用来排序的符合索引:IX_regbroker_id,check_date (regbroker_id,check_date)。
explain:
从key那行可以看出排序索引是没有用到的,在check_date上对百万千万级别的数据进行排序之后再根据过滤条件来过滤,还有like和or,就死了,遇上not in比较多的这个sql要执行几十秒,并发连接一起来,死了,cpu就撑爆了,一大堆别的sql在等待执行。整个实例就挂了。
但我把not in里面的减少到两个,发现索引又用上了:
1s执行完。
3个以上就又不走了。
后来是又改成了连表进行过滤。这里就不贴SQL了。
结论:
- 慎用not in,特别是里面的枚举值多的情况,尽量不用,因为not in前面的字段是主键的缘故(多次测试),此条件会影响mysql的执行计划,其它表的字段虽然用了 like,or,但它依然会在索引上过滤并排序后进行过滤。
- 改变了sql的查询条件,特别是sql关联的表是大表,需要对多种场景进行explain,尽量防患于未然。