程序员不要好心办了坏事
开发中我们看那些散发着浓烈的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也无可厚非了。但是,我们作为后来接手着,任何改动就要小心了,避免跳坑里了。
程序员不要好心办了坏事相关推荐
- OSChina 周一乱弹 ——程序员已经习惯熬夜了吧
2019独角兽企业重金招聘Python工程师标准>>> Osc乱弹歌单(2017)请戳(这里) [今日歌曲] @小小李探花 :分享许巍的单曲<第三极 (纪录片<第三极&g ...
- 作为一个程序员我为什么要写博客?
作为一个程序员我为什么要写博客?从2012-05-22的第一篇博文,到现在累计原创:523篇,转载:182篇,译文:8篇,转载的基本不会占用多少时间,我们来计算一下原创的+译文:这里假设平均写一篇博文 ...
- 一双拖鞋引发的血案——我与《程序员》不得不说的故事
我正在参与<新程序员>有奖征文,相关链接https://marketing.csdn.net/p/52c37904f6e1b69dc392234fff425442 <程序员>已 ...
- 编程:从前有一个傻呆程序员,老婆交给他一项任务,他办了四次才满意
从前有一个傻呆程序员,他老婆交给他一项任务:"去买3斤橙子,买最大最甜最便宜的脐橙". 普通人买水果直接去店里就买了,但程序员不同.程序员心道:"大,好分辨,甜,不好分辩 ...
- 对人再善良,也别犯这3种说话大忌,好心办坏事,嘴欠伤自己
增广贤文中流传最广的一句话,可能就是这句了:病从口入,祸从口出.千百年来,几乎每个人都深有体会,这是因为社会文明无论怎么发展,人性亘古不变.行走职场,害人之心不可有,防人之心不可无,管住嘴,少说错话, ...
- 心得丨程序员们,AI来了,机会来了,危机也来了,我们该咋办?
1.人工智能真的来了 纵观古今,很少有计算机技术能有较长的发展寿命,大部分昙花一现,比如:昔日的DOS.windows3.2.foxpro.delphi.80x86汇编,还有很多技术也在艰难地挣扎,比 ...
- 程序员去新公司办入职被拒,因离职证明写了这句话
(点击上方公众号,可快速关注) 转自:成都商报 交了简历,通过了面试,25岁的程序员戴翔被新应聘的公司通知入职,然而因为原公司给他出具的一份离职证明上,记载了一句"该员工在项目未完成情况下因 ...
- 真的要做一辈子的程序员吗?来自10年程序员的心声
经常听一些同学说:不知道下一份工作该去哪类公司做些什么,我的职场人际一团糟老板不重视我,我现在成长的非常慢所以又想跳槽了,我看不到公司的发展前景好迷茫,其实这一切的困惑都来源于没有做好职业规划或者你根 ...
- 程序员如何打破 30 岁职业瓶颈?
点击上方"CSDN",选择"置顶公众号" 关键时刻,第一时间送达! 本文来自作者 王鹏 在 GitChat 上分享 「程序员跳槽时,如何正确做好职业规划?」. ...
最新文章
- 第25章 Pytorch 如何高效使用GPU
- Java就业难不难?是否要参加Java培训?
- 【布局】圣杯布局双飞翼布局
- 论文|记忆网络之Memory Networks
- 巧用Squid的ACL和访问列表实现高效访问控制
- 启动u盘自动运行服务器,WinPE网启服务器自动配置程序
- ARM指令集的最新版本包括针对JavaScript的优化
- 2022年最新全国各省五级行政区划代码及mysql数据库代码(省/市/区县/乡镇/村)
- photoshop 插件_所有设计师必须拥有的20个免费和有用的Photoshop插件
- 15 使用计算机应遵守行业道德规范,初中信息技术会考试题 -
- C# string 保留数字英文字母
- 支付宝sdk——python-alipay-sdk
- 【Linux】Linux下挂载新硬盘(图形化使用Ubuntu自带Disks)
- win10家庭中文版安装Hyper-V 解决Hyper-V.cmd闪退问题
- Numpy库 numpy.corrcoef()函数
- Opencv实现停车位识别
- 峰值预测性能指标PPTS(Peak percentage of threshold statistic)
- windows10 改变桌面路径到其他盘 直接显示所有文件重定向路径问题
- IPD解读—需求管理(OR)流程方法论
- 【JAVA今法修真】 第八章 仙道万维网 圣地元宇宙