开发中我们看那些散发着浓烈的bad smell的代码,总有一种要修理它的冲动!这当然是好事,说明我们有能力识别不好的东西以及维持系统健康运行的意愿。但是,但是总是无处不在,我们好心有时候会办出坏事来。下面这个真实的案例就是某同学觉得表的字符集设计的不合理,在一次需求开发中就把他改了,然而不幸的是由此导致了一个不小的线上事故,下面分享给大家

1.事故的导火线

你敢想?导致线上事故的是一个简单的DDL 语句:

ALTER TABLE table_t CONVERT TO CHARACTER SET utf8mb4;

2.事故现场

由于业务系统响应极慢,使用方反馈(早期系统没有完善的告警机制),开发排查日志发现是sql查询速度很慢,然后查询慢日志监控,看到了如下的壮观场景:

3.事故原因分析

为什么会有这么多慢查询呢??因为查询语句的关联字段的字符集不同,导致索引失效,sql执行变成了全表扫描,进而导致数据库实例所在机器的CPU 长时间100%,影响业务访问。

4.事故线下重现

我们使用连接查询时,两个表的关联字段都建有索引,但是如果两个表的关联字段的字符集不同,就会导致索引失效,不会走索引。执行下面的建表语句:

CREATE TABLE `t1` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` VARCHAR(64) DEFAULT '',
`code` VARCHAR(16) DEFAULT '',
PRIMARY KEY (`id`),
KEY `idx_code` (`code`),
KEY `idx_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=UTF8;CREATE TABLE `t2` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` VARCHAR(64) DEFAULT '',
`code` VARCHAR(16) DEFAULT '',
PRIMARY KEY (`id`),
KEY `idx_code` (`code`),
KEY `idx_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=UTF8MB4;

然后插入一些数据:

INSERT INTO `t1` (`id`, `name`, `code`) VALUES (6, 'aa', '');
INSERT INTO `t1` (`id`, `name`, `code`) VALUES (7, 'bb', '');
INSERT INTO `t1` (`id`, `name`, `code`) VALUES (8, '0', '');
INSERT INTO `t1` (`id`, `name`, `code`) VALUES (9, '1', '');
INSERT INTO `t1` (`id`, `name`, `code`) VALUES (10, '2', '');
INSERT INTO `t1` (`id`, `name`, `code`) VALUES (11, '3', '');
INSERT INTO `t1` (`id`, `name`, `code`) VALUES (12, '4', '');
INSERT INTO `t1` (`id`, `name`, `code`) VALUES (13, '5', '');
INSERT INTO `t1` (`id`, `name`, `code`) VALUES (14, '6', '');
INSERT INTO `t1` (`id`, `name`, `code`) VALUES (15, '7', '');
INSERT INTO `t1` (`id`, `name`, `code`) VALUES (16, '8', '');
INSERT INTO `t1` (`id`, `name`, `code`) VALUES (17, '9', '');INSERT INTO `t2` (`id`, `name`, `code`) VALUES (6, 'ff', '');
INSERT INTO `t2` (`id`, `name`, `code`) VALUES (7, 'hh', '');
INSERT INTO `t2` (`id`, `name`, `code`) VALUES (8, 'gg', '');

线上的sql形式如下:

select * from t2 left join t1 on t1.code = t2.code where t2.name = 'ff';

我们查看执行计划:

explain extended select * from t2 left join t1 on t1.code = t2.code where t2.name = 'ff';

从下图的执行计划可以看到,查询条件t2.name = 'ff’使用了索引,而条件t1.code = t2.code并没有使用表t1的索引:

为什么两个字段的字符集不一样就不走索引了呢?这个命令SHOW WARNINGS; 会给你详细的说明分析,这个命令和执行计划配合使用,简直不能再香了。你一定要去使用!如下:

message全量内容如下:

/* select#1 */ select `test`.`t2`.`id` AS `id`,`test`.`t2`.`name` AS `name`,`test`.`t2`.`code` AS `code`,`test`.`t1`.`id` AS `id`,`test`.`t1`.`name` AS `name`,`test`.`t1`.`code` AS `code` from `test`.`t2` left join `test`.`t1` on((convert(`test`.`t1`.`code` using utf8mb4) = `test`.`t2`.`code`)) where (`test`.`t2`.`name` = 'ff')

这时候已经非常清楚了,MySQL在关联字段上进行了convert转化,索引当然就失效喽!

5.事故解决

问题的解决也是简单粗暴,DBA直接改回了原来的字符集:

ALTER TABLE t_test CONVERT TO CHARACTER SET utf8;

6.事故复盘

平时让我们说索引失效的场景你可能会咔咔咔的说出不少,但是实际使用的时候却时常会犯错,实际上还是意识不强烈。不管怎么说,都要认真对待自己写下的每行代码,包括任何要上线的资源,如初始化的数据,脚本等。就拿这次事故来说,开发同学本意是觉得utf8字符集不严谨,应该使用utf8mb4,但实际上表中的code字段存储的只是数字和字母组成的字符串,早期历史原因被设计成utf8也无可厚非了。但是,我们作为后来接手着,任何改动就要小心了,避免跳坑里了。

程序员不要好心办了坏事相关推荐

  1. OSChina 周一乱弹 ——程序员已经习惯熬夜了吧

    2019独角兽企业重金招聘Python工程师标准>>> Osc乱弹歌单(2017)请戳(这里) [今日歌曲] @小小李探花 :分享许巍的单曲<第三极 (纪录片<第三极&g ...

  2. 作为一个程序员我为什么要写博客?

    作为一个程序员我为什么要写博客?从2012-05-22的第一篇博文,到现在累计原创:523篇,转载:182篇,译文:8篇,转载的基本不会占用多少时间,我们来计算一下原创的+译文:这里假设平均写一篇博文 ...

  3. 一双拖鞋引发的血案——我与《程序员》不得不说的故事

    我正在参与<新程序员>有奖征文,相关链接https://marketing.csdn.net/p/52c37904f6e1b69dc392234fff425442 <程序员>已 ...

  4. 编程:从前有一个傻呆程序员,老婆交给他一项任务,他办了四次才满意

    从前有一个傻呆程序员,他老婆交给他一项任务:"去买3斤橙子,买最大最甜最便宜的脐橙". 普通人买水果直接去店里就买了,但程序员不同.程序员心道:"大,好分辨,甜,不好分辩 ...

  5. 对人再善良,也别犯这3种说话大忌,好心办坏事,嘴欠伤自己

    增广贤文中流传最广的一句话,可能就是这句了:病从口入,祸从口出.千百年来,几乎每个人都深有体会,这是因为社会文明无论怎么发展,人性亘古不变.行走职场,害人之心不可有,防人之心不可无,管住嘴,少说错话, ...

  6. 心得丨程序员们,AI来了,机会来了,危机也来了,我们该咋办?

    1.人工智能真的来了 纵观古今,很少有计算机技术能有较长的发展寿命,大部分昙花一现,比如:昔日的DOS.windows3.2.foxpro.delphi.80x86汇编,还有很多技术也在艰难地挣扎,比 ...

  7. 程序员去新公司办入职被拒,因离职证明写了这句话

    (点击上方公众号,可快速关注) 转自:成都商报 交了简历,通过了面试,25岁的程序员戴翔被新应聘的公司通知入职,然而因为原公司给他出具的一份离职证明上,记载了一句"该员工在项目未完成情况下因 ...

  8. 真的要做一辈子的程序员吗?来自10年程序员的心声

    经常听一些同学说:不知道下一份工作该去哪类公司做些什么,我的职场人际一团糟老板不重视我,我现在成长的非常慢所以又想跳槽了,我看不到公司的发展前景好迷茫,其实这一切的困惑都来源于没有做好职业规划或者你根 ...

  9. 程序员如何打破 30 岁职业瓶颈?

    点击上方"CSDN",选择"置顶公众号" 关键时刻,第一时间送达! 本文来自作者 王鹏 在 GitChat 上分享 「程序员跳槽时,如何正确做好职业规划?」. ...

最新文章

  1. 第25章 Pytorch 如何高效使用GPU
  2. Java就业难不难?是否要参加Java培训?
  3. 【布局】圣杯布局双飞翼布局
  4. 论文|记忆网络之Memory Networks
  5. 巧用Squid的ACL和访问列表实现高效访问控制
  6. 启动u盘自动运行服务器,WinPE网启服务器自动配置程序
  7. ARM指令集的最新版本包括针对JavaScript的优化
  8. 2022年最新全国各省五级行政区划代码及mysql数据库代码(省/市/区县/乡镇/村)
  9. photoshop 插件_所有设计师必须拥有的20个免费和有用的Photoshop插件
  10. 15 使用计算机应遵守行业道德规范,初中信息技术会考试题 -
  11. C# string 保留数字英文字母
  12. 支付宝sdk——python-alipay-sdk
  13. 【Linux】Linux下挂载新硬盘(图形化使用Ubuntu自带Disks)
  14. win10家庭中文版安装Hyper-V 解决Hyper-V.cmd闪退问题
  15. Numpy库 numpy.corrcoef()函数
  16. Opencv实现停车位识别
  17. 峰值预测性能指标PPTS(Peak percentage of threshold statistic)
  18. windows10 改变桌面路径到其他盘 直接显示所有文件重定向路径问题
  19. IPD解读—需求管理(OR)流程方法论
  20. 【JAVA今法修真】 第八章 仙道万维网 圣地元宇宙

热门文章

  1. 不用软件直接查询QQ好友的IP地址(一)
  2. Sketchup 程序自动化(六)颜色、材质贴图
  3. 赶紧登录百度网盘,否则空间可能会消失!
  4. 调用系统程序导入手机上的vcard文件
  5. Python学习日记(十一) 内置函数
  6. php微信公众平台开发类,php微信公众平台开发类实例
  7. GAIA:智能运维领域通用公开数据集
  8. 基于STM32的MD5校验
  9. Codeforces Round #693 (Div. 3)G. Moving to the Capital
  10. li标签:list-style