点击上方 "编程技术圈"关注, 星标或置顶一起成长

后台回复“大礼包”有惊喜礼包!

日英文

It all comes to the end about the past and you.For the future,about me,to be continued.When the whole world is about to rain, let’s make it clear in our heart together.

关于过去,关于你,告一段落。 关于未来,关于我,敬请期待。当全世界约好一起下雨,让我们约好一起在心里放晴。

每日掏心话

最闹心的烦躁是你根本不知道自己究竟在烦什么,无缘无故就全身负能量爆棚。

责编:乐乐 | 来自:鄙人薛某 | 作者:很懒的程序员

编程技术圈(ID:study_tech)第 1231 次推文

往日回顾:公司领导网上自曝:"真不想招35岁以上的基层员工!"网友怒了…

     

   正文   

上周四午休时分,我正在工位上小憩,睡梦中仿佛看到了自己拿着李白在荣耀峡谷里大杀四方的情景,就在我刚拿完五杀准备带领队友推对面水晶的时候,一句慌乱急促的“糟了”把我从睡梦中惊醒......
反常的 SQL 语句我眯开朦胧的双眼,才发现刚才的发声来源于我的组长庄哥,看到他在紧张的点开日志系统查看日志,我预感到有什么不妙的事情发生。
仔细一问才知道,原来就在我眯眼的期间,线上数据库服务器的 CPU 被打满,同时触发了生产数据库只读延迟的限定时间并且发出告警,而且告警的过程持续了半个小时。这让我倒吸了一口凉气,因为我们组做的系统很多都用的是同一个数据库服务器,日用户活跃量有好几十万,如果服务器崩溃了将会使所有的系统服务都不可用。于是我们赶紧通过 SQL 日志进行问题查找,最后排查出来是因为一张 SQL 的高量查询没有走索引导致。日志列表显示,这条 SQL 语句的扫描行数达到了上百万,基本就是全表扫描的情况,而且半个小时的时间查询了达上万次,每条 SQL 查询的耗时都在 3000ms 以上。我的天啊,难怪服务器会 CPU 打满,这么一条耗时的 SQL 语句查询量这么大,数据库的资源当然是直接就崩溃了。这是当时那条 SQL 的查询情况:临时处理看了这条语句,我又倒吸一口凉气,这不就是我写的系统调用的 SQL 语句吗?完了,这回逃不掉了,真是人在睡梦里,锅从天上来。
当然,因为是我自己写的 SQL,所以我一看就知道这条语句是有问题的。根据我的代码处理,这条 SQL 的调用还少了个重要的参数 user_fruit_id,这个参数没有传的话是不应该走这条 SQL 查询的。在我的设计里,该参数是数据表里一个联合索引的最左侧字段,如果该字段没有传值的话,那么索引就不会生效了。KEY `idx_userfruitid_type` (`user_fruit_id`,`task_type`,`receive_start_time`,`receive_end_time`) USING BTREE虽然定位到了 SQL 语句,但是线上的问题刻不容缓,总不可能找出 Bug 改完再上线吧。所以,我们只能做了一个临时处理,就是在原来的表上多加了一个联合索引,其实就是去掉了 user_fruit_id 字段,让这些高量的查询都能走新的索引。
就像下面这样:
KEY `idx_task_type_receive_start_time` (`task_type`,`receive_start_time`,`receive_end_time`,`created_time`) USING BTREE加上索引后,SQL 的扫描行数就大幅度的降低了,重启实例后就又能正常运行了。
最左匹配原则那么为什么最左侧的字段没传索引就不生效了,这是因为 MySQL 的联合索引是基于“最左匹配原则”匹配的。我们都知道,索引的底层是 B+ 树结构,联合索引的结构也是 B+ 树,只不过键值数量不是一个,而是多个,构建一颗 B+ 树只能根据一个值来构建,因此数据库依据联合索引最左的字段来构建 B+ 树。例如我们用两个字段(name,age)这个联合索引来分析:
图片来源于林晓斌老师的《MySQL 实战 45 讲》课程
当我们在 where 条件中查找 name 为“张三”的所有记录的时候,可以快速定位到 ID4,并且查出所有包含“张三”的记录。而如果要查找“张三,10”这一条特定的数据,就可以用 name = "张三" and age = 10 获取。
搜索公众号后端架构师后台回复“架构整洁”,获取一份惊喜礼包。因为联合索引的键值对是两个,所以只要前面的 name 确定的情况下就可以进一步定位到具体的 age 记录。
但是如果你的查询条件只有 age 的话,那么索引就不会生效,因为没有匹配最左边的字段,后面所有的索引字段都不会生效。所以我之前写的 SQL 语句才会因为少了最左边的 user_fruit_id 字段而走了全表扫描的查询方式。正常来说,假设一个联合索引设计成(a,b)这样的结构的话,那么用 a and b 作为条件,或者 a 单独作为查询条件都会走索引,这种情况下我们就不要再为 a 字段单独设计索引了。但如果查询条件里面只有 b 的语句,是无法使用(a,b)这个联合索引的,这时候你不得不维护另外一个索引,也就是说你需要同时维护(a,b)、(b) 这两个索引。
找出 Bug虽然临时做了处理,但问题并不算解决,很明显是系统出现了 Bug 才会有走这样的查询条件。因为是我自己写的代码,所以知道是哪条 SQL 后我就马上定位到了代码里的具体方法,后来才发现是因为我对 user_fruit_id 字段的判空处理不生效所致。
因为该字段是从调用方传过来的,所以我在方法参数里对该字段做了非空限制的注解,也就是 javax 包下的 @NotNull:public class GardenUserTaskListReq implements Serializable {private static final long serialVersionUID = -9161295541482297498L;@ApiModelProperty(notes = "水果id")@NotNull(message = "水果id不能为空")private Long userFruitId;/**以下省略*/.....................
}虽然加上该注解来做非空校验,但我却没有在参数加上另一个注解 @Validated。该注解如果没加上的话,那么调用 javax 包下的校验规则就都不生效,正确的写法是在 controller 层方法的参数前面加上注解:除此之外,因为 user_fruit_id 这个字段是另一张表的主键,我在代码里也没有对这张表是否存在这个 id 做查询判断。这样一来,无论调用方传什么值过来都会直接触发 SQL 查询,并且在不跑索引的情况下直接走全表扫描。不得不说,这真是个低级错误,说真的,我对这个原因真是感到嘀笑皆非,再怎么说也工作几年了,怎么还犯一些新手级别的错误呢,这脸打得真是让我相当惭愧。
总结虽然是低级错误,但造成的后果也算挺严重了,这次事件也让我更加的警醒,在以后的开发工作中必须要遵守该有的原则,大概有这么几点:①不能相信调用端。重要的参数都要先做验证,即使是非空值也需要做验证,不符合条件的就要直接返回或抛异常,不能参与业务 SQL 的查询,否则频繁的访问也会对服务造成负担。②SQL 语句要先做性能查询。对于数据量大的表,建好索引后,所有的 SQL 查询语句要用 explain 检测性能,并且根据结果来进一步优化索引。③代码必须要 Review。之前我没有放太大的精力在代码的 Review 上,虽说跟迭代排期的紧凑也有关系,但不管怎么说,Bug 确实是我的疏忽造成的,尤其是像空值这种细小的错误在 Java 里可以说家常便饭。千里之堤毁于蚁穴,有时一个小 Bug 很容易就引发整个系统的崩盘,这一次的问题也让我更加深刻的认识到了 Review 代码的重要性,不管业务开发的工作量有多麻烦,这一步操作绝对不能忽视。
PS:欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,欢迎转发分享给更多人。版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢!欢迎加入后端架构师交流群,在后台回复“学习”即可。最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。在这里,我为大家准备了一份2021年最新最全BAT等大厂Java面试经验总结。
别找了,想获取史上最简单的Java大厂面试题学习资料
扫下方二维码回复「面试」就好了猜你还想看
阿里、腾讯、百度、华为、京东最新面试题汇集
我差点信了......面试官:Java 反射是什么?我回答不上来!12 个非常适合做外包项目的开源后台管理系统嘿,你在看吗?

因为一条SQL,我差点被祭天......,我太难了!相关推荐

  1. 因为一条SQL,程序员差点被祭天......

    来源:鄙人薛某  作者:很懒的程序员 上周四午休时分,我正在工位上小憩,睡梦中仿佛看到了自己拿着李白在荣耀峡谷里大杀四方的情景,就在我刚拿完五杀准备带领队友推对面水晶的时候,一句慌乱急促的" ...

  2. mysql多条新增字段sql合并为一条新增

    如下,同一张表,有4条分开的新增字段的sql, alter table aadd column column1 tinyint null default null comment 'column1:0 ...

  3. 一条sql语句添加多个字段

    Forbiden: Merge the alter statement for table 'app_info' to ONE. 需要给表中添加两个字段,之前写了两句: alter table app ...

  4. 数据分析sql面试必会6题经典_师兄大厂面试遇到这条 SQL 数据分析题,差点含泪而归!...

    作者 |  云祁 来源 | cnblogs.com/beiisbei/p/13269964.html 一.背景 师兄在面试时遇到了这条SQL题,回来我帮他参谋了下,觉得非常有意思,让我们一起来看看这道 ...

  5. sql语句实现多条数据合为一条数据

    今天遇到个函数感觉很有用,给你们举个例子吧: 当我们给用户多个角色的时候,我们的用户角色表的展示方式有两种, 一种是把所有角色何在一起变成一个字符串,然后在该表查看用户就能看到一条关于用户角色的数据 ...

  6. 师兄面试遇到这条 SQL 数据分析题,差点含泪而归!

    写在前面:我是「云祁」,一枚热爱技术.会写诗的大数据开发猿.昵称来源于王安石诗中一句 [ 云之祁祁,或雨于渊 ] ,甚是喜欢. 写博客一方面是对自己学习的一点点总结及记录,另一方面则是希望能够帮助更多 ...

  7. sql 非主键每年自增_或许你不知道的 10 条 SQL 技巧

    上文我们简述了 SQL 的一些进阶技巧,一些朋友觉得不过瘾,我们继续来下篇,再送你 10 个技巧 一. 使用延迟查询优化 limit [offset], [rows] 经常出现类似以下的 SQL 语句 ...

  8. 一条SQL语句的千回百转

    点击▲关注 "数据和云"   给公众号标星置顶 更多精彩 第一时间直达 SQL语言相信大家都不陌生,从本质上来说,它是一种结构化查询语言,是用来数据库之间的通信的编程语言.作为一名 ...

  9. mysql 合并两个update_如何将多条update语句合并为一条

    需求: 如何将多条update语句合并为一条update语句: 如,update table1 set col='2012' where id='2014001' update table1 set  ...

  10. server多笔记录拼接字符串 sql_sqlserver 将多行数据查询合并为一条数据

    有这样一个需求:表T_FUN_TASK为任务表,有字段(TASKID,TASKNAME),表T_FUN_LOGBOOK为日志表,有字段(LOGID,TASKID,LOGDATE),一个任务可持续多天, ...

最新文章

  1. 第02期 基础算法(Leetcode)刻意练习开营计划
  2. Python函数参数的五种类型
  3. FastJson解析
  4. C语言程序设计 计算个人所得税 浙大版,《C语言及程序设计》实践参考——个人所得税计算器switch语句版...
  5. python print换行_聊聊 print 的前世今生
  6. Java 线程——创建和运行线程|| lambda表达式就是一个匿名内部类||Thread 与 Runnable 的关系||FutureTask 配合 Thread
  7. 快速解决正则----模糊匹配、字符类、量词
  8. java 回滚异常_Spring事务管理只对出现运行期异常进行回滚
  9. linux mysql误删,linux下MySQL安装与删除 (Ubuntu)
  10. bind blz mysql_MySQ DBAL重点剖析课程 企业级MySQL系统安全与DBA运维日常事务管理 运维DBA必备宝典...
  11. Mybatis中resultMap
  12. web 前端 如何分享到instagram_面对前端的后端化趋势,2020该如何学习web前端?
  13. Pytorch的一些损失函数
  14. ROS学习笔记之——PX4开发初入门
  15. Python pyqt5绘画界面(文章可能啰嗦,不喜勿喷)
  16. 如何拆分PDF成单页?这三个方法分享给你
  17. 【数论】欧几里得算法
  18. Centos7.5 -Vim编辑器和恢复ext4下误删除的文件-Xmanager工具
  19. win7 x64系统配置caffe的matlab接口。
  20. 2018面试题目总结1

热门文章

  1. 《路由器开发 - 路由器刷机指南》优酷路由宝 YK-L1刷机
  2. 随机游走(Random Walk)算法
  3. 2022-01-24:K 距离间隔重排字符串。 给你一个非空的字符串 s 和一个整数 k,你要将这个字符串中的字母进行重新排列,使得重排后的字符串中相同字母的位置间隔距离至少为 k。 所有输入的字符串
  4. qq对计算机程序的更改,解决电脑总弹出“是否允许程序对计算机进行更改”
  5. 百度自定义技能真机测试
  6. 【分布式】psutil cpu_percent如何使用;python如何测试cpu的使用率
  7. jQuery水平手风琴图片轮播切换
  8. Python iter()函数
  9. CVPR 2019 论文汇总(按方向划分,0506 更新中)
  10. 差分法求一阶导数二阶导数,matlab