为什么很多人连基础的 SQL 都写不好,却开口闭口就是缓存架构分布式?

2021-09-02 18:35:48 +08:00
 wh469012917

说下情况,我们公司同个部门的好几个同事,连个基础的 SQL 都写不好,代码中一堆数据库 N+1 的问题,连个 WHERE IN 查询都不会用,涉及到批量查询,都是遍历然后一条条的去跑 SQL,同一个方法重复查询了好几次,数据库设计更是不行,外键都是用逗号分隔拼接成字符串,然后保存到主表上。

正因为 SQL 写的烂,所以接口性能很差劲,但是他们好像都不在意这些 IO 方面的优化,整天在想着怎么优化语言性能,比如反射、JSON 序列化、语言基础库的性能;要么就是上集群、加缓存,然后又没有任何设计模式,直接业务代码中强硬加入缓存读写,就算是缓存也是先从缓存读出数据,然后遍历一条条去数据库再查出来,性能更差了

其实整体项目量不大,好好写好 SQL,基本上能搞定 90% 的性能问题了,大部分的开发经验也都好几年了,不至于这种基础知识点不懂,可为啥就是不重视 SQL 性能

17943 次点击
所在节点    程序员
206 条回复
glfpes
2021-09-05 16:35:09 +08:00
SQL 写好并不容易,做一个 sql boy 比 crud 要困难。

服务治理其实就是 crud
ychost
2021-09-05 19:24:24 +08:00
高并发+大流量 本质是 DB 、缓存 的使用,语言层面能够优化的性能微乎其微
cyru1s
2021-09-05 19:38:37 +08:00
还不是各个大厂面试官逼得。

实际工作:在 Druid 之类的存储上写类 SQL 的 DSL 、往往还因为公司版本过低不支持最新文档的 functions,最终你要合理的把查询拆成几个然后本地处理中间数据、最终完成一个功能。

面试提问:缓存架构分布式。
wh469012917
2021-09-05 22:27:51 +08:00
@anouser 用户量大概十几万吧,日活 1 万左右,做垂直领域的,量不算多,但是还是有用户用的
wh469012917
2021-09-05 22:29:00 +08:00
@namelosw 对的,解决一个 n+1 问题,比你用什么架构缓存都好使,除非就是为了装逼
wh469012917
2021-09-05 22:31:07 +08:00
@msg7086 因为 n+1 问题,我们目前部分接口已经出现明显的性能问题了,但是有些人都不重视这块,一直在优化语言级别的性能
wh469012917
2021-09-05 22:31:35 +08:00
@unregister 也可以,join 不是万能,解决问题的方案有很多种,
wh469012917
2021-09-05 22:34:59 +08:00
@shot 团队负责人虽然也是技术出身,但是自己并不写代码,主要是注重开发进度和应用稳定性,技术主要让组内一个有一定年限的同事来处理,但是这代码就是这个同事写出来了,所以就不要指望他能做啥优化了。

目前数据量在三千万左右,每个月增长差不多 200w 左右,sql 性能问题已经慢慢显露出来了。
wh469012917
2021-09-05 22:35:41 +08:00
@noparking188 无,一个数据库出现 4 种字符集,join 都用不了;字段命名没有规则,大家各做各的
wh469012917
2021-09-05 22:36:33 +08:00
@ychost 对的,数据库是 IO 最重的地方,应该花大力气来处理;加缓存虽然效果明显,但是会导致代码复杂度增加和缓存同步问题
noparking188
2021-09-05 22:58:08 +08:00
msg7086
2021-09-06 04:40:41 +08:00
楼上说的对,出现这些问题,但是同事都不懂,那应该搞一些研讨会学习会,让一两个懂的人出来给其他人讲解一下。然后 leader 也应该制定规范,让大家知道哪些东西是必须要遵守的。
从你说的来看,这两个 leader 都有些问题,工作没有做好,导致下面拉稀。
wh469012917
2021-09-06 09:19:29 +08:00
@msg7086 前提是要有人懂,并且有一定的话语权来推动呀;我们这边部门领导一般不管这些,主要负责全局的把控;后端组长自己就是写这些代码的人;我是一直想要推动,奈何没什么话语权,所以挺难的
wh469012917
2021-09-06 09:20:14 +08:00
@noparking188 一个数据库出现了四五种字符集,你觉得能有什么规范吗
noparking188
2021-09-06 09:31:35 +08:00
@wh469012917 #194 不大懂你说的四五种字符集什么意思,是 collate character ?
如果是,在规范里指定用哪种就行,原先不统一的字符集后面陆续更改,解决历史遗留问题
onhao
2021-09-06 10:18:37 +08:00
@xuanbg 题主好像是说
“找出所有科目成绩在 80 分以上的学生。
难道是我理解错误?
BiChengfei
2021-09-06 14:14:03 +08:00
@l00t 这不是本科《数据库原理》中的 demo 吗?我会写,我是不是面试通过了,嘿嘿嘿
create table t_student (
id integer primary key ,
name varchar(40)
);

create table t_course (
id integer primary key ,
course varchar(40)
);

create table t_grade (
id integer primary key ,
student_id integer,
course_id integer,
grade integer
);

insert into t_student(id, name) values (1, '张三');
insert into t_student(id, name) values (2, '王五');
insert into t_student(id, name) values (3, '小李');
insert into t_student(id, name) values (4, '王华');

insert into t_course(id, course) values ( 1, '数学' );
insert into t_course(id, course) values ( 2, '语文' );
insert into t_course(id, course) values ( 3, '英语' );
insert into t_course(id, course) values ( 4, '化学' );
insert into t_course(id, course) values ( 5, '物理' );

insert into t_grade(id, student_id, course_id, grade) values ( 1, 1, 1, 100 );
insert into t_grade(id, student_id, course_id, grade) values ( 2, 1, 2, 80 );
insert into t_grade(id, student_id, course_id, grade) values ( 3, 1, 3, 10 );
insert into t_grade(id, student_id, course_id, grade) values ( 4, 1, 4, 100 );
insert into t_grade(id, student_id, course_id, grade) values ( 5, 1, 5, 100 );

insert into t_grade(id, student_id, course_id, grade) values ( 6, 2, 1, 100 );
insert into t_grade(id, student_id, course_id, grade) values ( 7, 2, 1, 100 );
insert into t_grade(id, student_id, course_id, grade) values ( 8, 2, 1, 100 );
insert into t_grade(id, student_id, course_id, grade) values ( 9, 2, 1, 100 );
insert into t_grade(id, student_id, course_id, grade) values ( 10, 2, 1, 100 );

select
a.student_id,
b.name
from t_grade a
left join t_student b on a.student_id = b.id
left join t_course c on a.course_id = c.id
group by a.student_id
having min(a.grade) >= 80
stevenbipt
2021-09-06 14:15:22 +08:00
基础的 sql 都写不好,简单的调优分析都做不好就谈那些理论上的这种操作个人是接受不了,就算接口慢优化也要分析好哪些地方该优化,而不是直接上理论安排上一堆东西,存储过程这些复杂的做不好问题不大,但是基础的 sql 查询都写得烂那还是建议换一家不用关系型数据库的公司吧
l00t
2021-09-06 14:49:10 +08:00
@mynamewang0 你这个 inner join 没意义啊……
@onhao “所有” 修饰 科目……
@BiChengfei left join course 这步不对

@xuanbg 加科目表是因为有人可能缺考。当然这个也基于一个没考就没记录的假设。如果没考也有一条得分为 0 的记录,那科目表有没有也没关系。我一般会在追问时才要求考虑没考就没记录的情况。你这条语句的思路是对的,但是写得太随意了,过不了语法编译的……

@vishun 我一般不会这么写,但是你这样写也行……反正结果是对的……
BiChengfei
2021-09-06 17:20:34 +08:00
@l00t 之前的不对是因为没有考虑缺考吗,大意了

-- t_student 、t_course 全连接,然后左连接成绩表,缺考就为 null
select
a 。id,
a 。name
from t_student a
left join t_course b on true
left join t_grade c on a 。id = c 。student_id and b 。id = c 。course_id
group by a 。id
having min(c 。grade) >= 80;

-- t_grade 左连接 t_student,通过学生 id 分组,然后最低分和参考课程数过滤
select
a 。id,
b 。name
from t_grade a
left join t_student b on a 。student_id = b 。id
group by a 。student_id
having
min(a 。grade) >= 80
and count(a 。course_id) = (select count(*) from t_course);

第一种是第一想法,但会占用额外的内存,第二种会好很多

请不要在每一个回复中都包括外链,这看起来像是在 spamming
我只能把点换成句号

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://tanronggui.xyz/t/799533

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX