7

逻辑大量的写在 sql 语句里

 2 years ago
source link: https://www.v2ex.com/t/835439
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

V2EX  ›  Java

逻辑大量的写在 sql 语句里

  moxiaowei · 10 小时 21 分钟前 · 3440 次点击

今天看了下同事写的代码,才发现他居然喜欢把大量的逻辑写在 sql 语句里,跟他讲了下,他说是以前同事教的,我认为这样写可读性实在太差了,但是他也不愿意听我的!想听听各位大佬怎么讲。 下面是一段 sql

      SELECT
        m.id,
        m.menuname,
        m.link,
        m.parent_id,
        m.menutype,
        m.sort
--         CASE
--         WHEN pm.parent_id > 0 THEN
--         1 ELSE 0
--         END hasChildren
        FROM
        menu m
--         LEFT JOIN ( SELECT DISTINCT parent_id FROM menu ) pm ON pm.parent_id = m.id
        WHERE
        m.is_deleted = 0
        <if test="userId !=null and userId !=''">
            and m.id in (SELECT DISTINCT
            rm.menu_id
            FROM
            role2menu rm
            LEFT JOIN role r ON r.id = rm.role_id
            LEFT JOIN user2role ur ON ur.role_id = r.id
            WHERE
            rm.is_deleted = 0
            AND ur.user_id = #{userId} )
        </if>
        ORDER BY
        m.sort

这只牵扯到 3 张表,就这么多 left join ,我后面又去翻了翻 10 来次 left join 的也很多。
89 条回复    2022-02-22 03:01:30 +08:00

liuliangyz

liuliangyz      10 小时 19 分钟前   ❤️ 1

没吊事,等哪天上了 sql 筛查,这类逻辑写到 sql 当中的直接被干掉~
我觉得这类人特别二

x86

x86      10 小时 14 分钟前

别管,听你的去改万一出啥问题,你也要分个锅

efaun

efaun      10 小时 13 分钟前

能 run 就行

levon

levon      10 小时 11 分钟前   ❤️ 1

这 sql 不算复杂,而且不算是业务

gimp

gimp      10 小时 10 分钟前

“这个功能明天就要”

Jihua

Jihua      10 小时 8 分钟前

没怎么写过 SQL 的菜鸟请教一下:对于同一个业务功能,把逻辑写到 SQL 里还是写到 SQL 外运行耗时更少?

moxiaowei

moxiaowei      10 小时 8 分钟前

@levon 这非要堆到 10 来个 left join 搞死 sql 才算复杂么?

est

est      10 小时 7 分钟前   ❤️ 9

这有啥不好的。sql 就是最古老的微服务,低代码啊。

最开始只有些教授发明了 B 树;

后来有穷 B 研究生把改成一个库可以被 C 语言调用

后来就有聪明商家包装成了一个 tcp 库拿出去卖钱

其次,后装市场为了迎合臭不要脸不懂技术分析师的需求,发明了 sql

没想到就火了。于是商家就把加上存储过程就是 RPC ,而且是 serverless 的小代码哦。insert/update/select/delete 对应 RESTful 的 CRUD ,sql 其实就是 GraphQL ,认证权限功能,分裤分婊功能,齐活了。

test3207

test3207      10 小时 7 分钟前   ❤️ 1

逻辑全写在代码里,都上事务吗?
多次 query 的额外网络和 IO 开销需要考虑吗?
有没有好哥哥讲一讲

felixcode

felixcode      10 小时 6 分钟前 via Android

这样写可能不方便其它人维护,但用 join 的方式先做筛选再给程序的确是运算开销最小的。

nitmali

nitmali      10 小时 3 分钟前   ❤️ 1

有一瞬间我以为我在看我们公司的代码 [doge]

woodensail

woodensail      10 小时 2 分钟前   ❤️ 6

@Jihua 大多数情况下,还是数据库里更快一些,但是问题在于,应用服务器可以轻松的平行扩展,数据库可就难了。
所以一般是数据库先简单筛下,然后交给应用服务器做后续处理。

cando

cando      9 小时 58 分钟前

挺正常的 习惯就好了
有时候复杂需求就需要这种
注意项目统一使用、语句优化好执行速度合理、写点注释

murmur

murmur      9 小时 56 分钟前

正常,我也听过这样的逻辑,sql 写业务,直接热发布不需要重启 tomcat

kiracyan

kiracyan      9 小时 55 分钟前   ❤️ 1

工业和老的系统很多逻辑都写在数据库存储过程 虽然可读性很差 但是是一种很廉价的 RPC 和热更新方案

SuperXRay

SuperXRay      9 小时 53 分钟前

逻辑写在 sql 语句里有啥问题???
写一大坨业务代码就不恶心吗?就可读性好了吗?

yazinnnn

yazinnnn      9 小时 52 分钟前

以后业务量大了,俩表跑到不同的数据库上了咋整?

chenmobuys

chenmobuys      9 小时 51 分钟前

这也算正常 SQL 吧,楼主还是没看到复杂的 SQL

Chad0000

Chad0000      9 小时 47 分钟前 via iPhone

只要给够钱就不是问题。我现在就涉及到这样的屎山代码,幸运的是我在海外,慢慢来,改好了反而是贡献的机会。

yor1g

yor1g      9 小时 43 分钟前   ❤️ 2

又不是存储过程 一个小查询没啥问题 不能 join?不能子查询? 不如写下你的做法给大家看看

jeffxjh

jeffxjh      9 小时 40 分钟前

想看不用连接查询的做法 大神给翻译翻译

ainyyy

ainyyy      9 小时 40 分钟前   ❤️ 2

我不觉得这个 sql 有什么问题。。 分开查询数据库更蠢吧。

kingwrcy

kingwrcy      9 小时 33 分钟前

sql 没问题,你是不是对复杂有什么误解?

这个一次性能返回结果不是挺好?

你如果业务代码写也不见得别人能懂啥意思,sql 挺能表达你的业务的

leafre

leafre      9 小时 32 分钟前

“这只牵扯到 3 张表,就这么多 left join ,我后面又去翻了翻 10 来次 left join 的也很多。”

join 最多 3 张表,再多不合理

james2013

james2013      9 小时 31 分钟前

这个不算大量吧
当我看到有的统计 sql
各种 if 判断和 join,lefj join, 1 条 sql 语句竟然有 300 行+,看的都吐了

adoal

adoal      9 小时 31 分钟前 via iPhone

@moxiaowei 10 来个 join 就搞死?如果不是 MySQL 的话没那么怕多 join 的。

retrocode

retrocode      9 小时 22 分钟前

这都是小 case,再烂的我都见过,有的厮直接 sql 里拼结构一个 sql 一两百行很正常.

你贴的这种写法有历史渊源的,有时候产品让加筛选,还特别急, 懒一点的人就是直接 sql 里改,然后丢 xml 上去更新

比如楼上说的 “这个功能明天就要”

早上提需求,中午问进度,第二天早上就要上线, 求稳定肯定是用改动最小的方法来的

不过恶心是真的恶心, 建议跑路, 我盲猜是政府项目

Paracosm

Paracosm      9 小时 19 分钟前

= = 。。。我经常写几百行的 sql ,不过我不是写后端的就是了

constantine008

constantine008      9 小时 18 分钟前

我来支持下楼主,建议压测看看会不会有慢查询,像这种语句我估计大概率是慢查询,高并发情况下 CPU 很容易就打满

jsjjdzg

jsjjdzg      9 小时 17 分钟前

唉,写的搜索 Logstash 通道容器,全是复杂 SQL ,要一个 SQL 搜集各种上游数据,一点办法都没。。。

aliveyang

aliveyang      9 小时 17 分钟前

这个不算复杂吧,你是没看过银行存储过程的,那才是脑壳痛

muyiluop

muyiluop      9 小时 15 分钟前

借楼问一下,如果不用连表,但是查询字段又存在其他表中的情况,一般怎么做?
比如:a 、b 两个表,b 中存了 a 的 id ,查询 b 表时有个条件是 a 中的 name 字段
不连表我能想到的方法是:根据 name 条件查询出 a 的 id ,然后通过 b.aid in 的方式来查询

wudaye

wudaye      9 小时 11 分钟前

SQL 层次不超过 2 层能接受,3 层就比较难受,适当的连表或子查询是合理的,但是你贴的这个 SQL 就有点过了,个人认为可维护性比性能重要得多

moxiaowei

moxiaowei      9 小时 10 分钟前   ❤️ 2

上面有好几个喷子,麻烦看看标题好么?麻烦,那些觉得写 left join10 来次的是正常代码的,去问问你公司的 leader ,他允不允许,站在自己的角度上来想这个问题,简直是没脑子!你这样写纯属前人挖坑葬后人,坑了一波又一波!你也在这公司干不过 3 年!

moxiaowei

moxiaowei      9 小时 9 分钟前

@wudaye 终于看到了一个评论能看的,上面那些喷子只是为了完成任务,根本不为了长远发展,写写一大堆的业务逻辑到 sql 里面,后面人要看到吐血的!

moxiaowei

moxiaowei      9 小时 8 分钟前

@adoal 你牛逼 对你我是真的很佩服的

acdfjelxe

acdfjelxe      9 小时 8 分钟前

各种场景几百行 SQL 都挺常见的,但你 SQL 得让数据库有优化空间 🌝

moxiaowei

moxiaowei      9 小时 7 分钟前

@yor1g 我说不能了?主观臆想啥呢?自嗨?

moxiaowei

moxiaowei      9 小时 6 分钟前

@kingwrcy 贴你写的 sql 出来 问问下个接受的想不想打你

fisherwei

fisherwei      9 小时 4 分钟前

我这有个保存下来有 4MB 的 sql ,谁爱改谁改去,反正现在能用

dqzcwxb

dqzcwxb      9 小时 3 分钟前

@moxiaowei 喜欢把逻辑写数据库的人其实是 DBA 而不是码农

wolfie

wolfie      9 小时 3 分钟前   ❤️ 10

一点问题没有,就俩 left join 还是在子查询里。

一边觉得同事菜,同事应该听我的。

发到 v2 发现自己菜,v2 所有人应该听我的。

quan01994

quan01994      9 小时 3 分钟前

见过更复杂的 。 最后的意见别改。

tabris17

tabris17      9 小时 2 分钟前

谁写的谁改,你比他早跑路就行了

liprais

liprais      9 小时 0 分钟前

哈哈楼主这喷的两个 left join 里面只有一个是真 left join .....

InvincibleDream

InvincibleDream      8 小时 51 分钟前

假如你和同事都会 java 和 c ,而且项目里同时用两种语言。你会和同事讲 C 的代码可读性太差,不要再写了吗?

oneisall8955

oneisall8955      8 小时 46 分钟前 via Android

代码和人,一个能跑就行

aecra

aecra      8 小时 42 分钟前 via Android

@james2013 我们数据库老师做的项目就这样,一条 SQL 语句占好几屏,还说这是标准,都看吐了

yeyang5211

yeyang5211      8 小时 40 分钟前

这种简单的 join 写在代码里和 sql 里可读性都不差,
join 十几张表的逻辑拆成代码也不好看 可读性照样差,你看他查了十几次数据库, 筛选了一堆数据
经常读着读着不知道原来的目的了.
一般遇到这种我的倾向是拆成 3 个左右小一点的 sql, 代码清晰了, sql 也好读了. 别人写的屎山就当没看到了 , 改这种东西折寿.

golangLover

golangLover      8 小时 36 分钟前 via Android

可读性是一件事,debug 困难是更大的问题。我会要求他重写

deplivesb

deplivesb      8 小时 35 分钟前

这个 SQL 很复杂么?一个 leftjoin 就是个复杂的业务了?那你是没见过我司长达几百行的基础业务 SQL ,已经运行了好几年了,很稳定,可比你所谓的“把业务写在代码里”可读性强多了,维护起来也比又臭又长的代码方便。即使业务变更,前后对比 SQL 不比翻代码清晰?? OP 还在#34 楼喷别人干不过三年,我看你把复杂业务写成代码的你能干多少年。

ikas

ikas      8 小时 34 分钟前

看起来是权限表,除非你们用户非常的多..否则权限相关这点数据量 2 次 left join 没啥问题

当然..我看了下我们的代码是这样的....


select id,name,type
from sys_resource
where exists(
select 1
from sys_role_resource
where sys_resource.id = sys_role_resource.resource_id
and exists(
select sys_role.id
from sys_role
where sys_role_resource.role_id = sys_role.id
and sys_role.id in (
select sys_user_role.id from sys_user_role where sys_user_role.user_id = :userId
)
)
)

hidemyself

hidemyself      8 小时 26 分钟前

单单就这个 SQL 而言,不复杂,而且也没什么逻辑。
那种 ERP 和 OA 的项目里的 SQL ,才叫复杂

potatowish

potatowish      8 小时 26 分钟前 via iPhone

SQL 语句尽可能不要包含太多逻辑,数据层就干数据层的事,逻辑应该放在应用层,包含大量逻辑的 SQL 短期看省事,长期非常难以维护,慢慢就成了没人敢动的屎山。

楼上不少人说什么不够复杂的,显然是偏题

efaun

efaun      8 小时 24 分钟前   ❤️ 1

lz 是真的菜, 而且还是不接受意见的菜 🤧 自己在小公司干了几个月, 见到没学过的东西就说不合理, 咋滴, 公司是你开的? 在 v2 找不到同水平的菜鸡(好像找到了一个?)认可就破防了, 咋滴, v2 是你建的?

fanchenio

fanchenio      8 小时 22 分钟前

我个人觉着楼主发的例子还算可以,没有多复杂或者大量逻辑,如果楼主觉着复杂或者逻辑繁杂的话,求贴出来一个解决方案,就按照你发的例子,如果你写代码要怎么写,虚心求教,想看一下。

guaguaguaxia1

guaguaguaxia1      8 小时 4 分钟前

反对楼主的都是真心的? SQL 语句里写逻辑看你后面怎么维护,屎山都是不经意间堆起来的,等你发现兜不住了再转身,屎山已经把你淹没

l00t

l00t      8 小时 0 分钟前

菜狗。这种程度的都觉得可读性差,是你的问题。

l00t

l00t      7 小时 59 分钟前

@guaguaguaxia1 写代码里怎么维护? SQL 代码也是代码,你能写在 Java 里维护,同样的逻辑写在 SQL 里就不会了么?

adoal

adoal      7 小时 55 分钟前 via iPhone

@moxiaowei 阿里那个什么 Java 规范里说连 JOIN 不得超过几个,是因为他们当时用的 MySQL ,对复杂 SQL 支持很差,多表连 JOIN 真的会搞死…但世间又不是只有 MySQL 这种残废。不说可读性、可维护性,只说性能,多表连 JOIN 根本不是 evil 。

Baloneo

Baloneo      7 小时 49 分钟前   ❤️ 1

```
SELECT
DISTINCT
a.meter_name AS meter_name,
a.pro_name AS pro_name,
a.pro_energy_val AS pro_energy_val_default,
b.date AS date,
sum(b.ep_o) AS counts
FROM
(
SELECT
DISTINCT
sh.collect_code AS collect_code,
sh.address AS address,
pee.meter_id AS meter_id,
pee.meter_name AS meter_name,
%s
sum(sh.ep_o) AS ep_o
FROM organization art
LEFT JOIN organization arm ON arm.p_id=art.id
LEFT JOIN product_energy_exp pee ON arm.id=pee.meter_id OR art.id=pee.meter_id
LEFT JOIN area_collect ac ON ac.area_id=pee.meter_id
LEFT JOIN collect_config_modbus ccm ON ccm.id=ac.collect_id
INNER JOIN stat_hour sh ON sh.collect_code=ccm.collect_code AND sh.address=ccm.address
WHERE 1=1
%s
AND ac.calc = 1
AND sh.stat_time IS NOT NULL
AND ccm.collect_code IS NOT NULL
AND ccm.address IS NOT NULL
%s
) b
INNER JOIN
(
SELECT
DISTINCT
ccm.collect_code,
ccm.address,
pee.pro_energy_val,
pee.meter_id,
pee.meter_name,
pee.pro_energy_name AS pro_name
FROM organization art
LEFT JOIN organization arm ON arm.p_id=art.id
LEFT JOIN product_energy_exp pee ON arm.id=pee.meter_id OR art.id=pee.meter_id
LEFT JOIN area_collect ac ON pee.meter_id=ac.area_id
LEFT JOIN collect_config_modbus ccm ON ccm.id=ac.collect_id
WHERE 1=1
AND ac.calc = 1
%s
) a ON a.collect_code = b.collect_code
AND a.address = b.address
GROUP BY meter_name,pro_name,pro_energy_val,date
ORDER BY meter_name,pro_name
%s
```

whoisjohnlee

whoisjohnlee      7 小时 34 分钟前

逻辑写 SQL 里面最大的问题是需要进行缓存优化的时候,DB 已经是最后一层了,想优化都没办法。。。

benzalus

benzalus      7 小时 29 分钟前

业务逻辑丰富的 sql 可读性一般,调试困难,是我最不想碰的……
曾经见识过一个面向存储过程的 php 项目,项目里每个 sql 百行起步。业务增长越快,死得越快

ytmsdy

ytmsdy      7 小时 15 分钟前

正常!以前很多 java 的项目,后端用的是 oracle ,很多业务逻辑都是写在存储过程里面。那个调试才叫一个痛苦!
有些大的存储过程,能打两张 A3 纸!

Leviathann

Leviathann      7 小时 14 分钟前 via iPhone

还有统计类的 sql
大量用到 clickhouse 之类的内置函数

jellywong

jellywong      7 小时 13 分钟前

不知道为什么这么多楼同意把业务逻辑放在 SQL 里的,我个人是不赞同这种方式,增加维护难度和踩坑风险。不知道大家是技术栈不同的原因,还是因为什么。

jellywong

jellywong      7 小时 12 分钟前

@jellywong 这里单说 MySQL

Leviathann

Leviathann      7 小时 8 分钟前 via iPhone

我们项目(公司后台)里会联表查的只有搜索条件巨多遍布几个表以及要分页的情况
其他的逻辑都不会写 sql 里

dcsuibian

dcsuibian      6 小时 56 分钟前

啊啊啊?我赞同能跑就别乱动的观点,但可读性差这点还能有争论的?

idblife

idblife      6 小时 54 分钟前 via iPhone

还有把业务逻辑都封装在存储过程里的呢

wonderfulcxm

wonderfulcxm      6 小时 42 分钟前 via iPhone

最近读桥水基金创始人瑞·达利欧的《原则》,经历一次倒闭级的失败后,他的思维转变从“我知道我是对的”,到“我怎么知道我的是对的。”。
楼主显然还停留在“我知道我是对的,如果你们说我错了,那我也是对的”上面。

notejava

notejava      6 小时 20 分钟前

这还好吧,那种查询复杂的管理后台,都是多张表 left join 的,代码少,需求变更时改动也快。

onhao

onhao      6 小时 6 分钟前

要不看看我这 5 张表的 SQL
https://wuhao.pw/archives/107/

https://wuhao.pw/archives/277/
估计很多同仁看到这一堆的 SQL ,都要劝我,逻辑判断, 函数 ,存储过程 最好都别写到 sql 里
不过说实话,用了是真爽阿, 少写很多业务代码。
至于坑同事,或者后来者。
不至于坑,合适,不影响 sql 执行效率的逻辑判断, 函数 ,存储过程 带来极致的效率,如果这些特性都怕维护,而不用,那要这些特性干什么?存在即有其合理的地方。

gengchun

gengchun      5 小时 36 分钟前

这条 SQL 其实不算太难理解吧?排版也不错。而且代码可读性,其实是有指标的,比如说变量或者函数名的长度和命名,排版时用是否对齐这些。业务逻辑是否用 SQL 为什么会和可读性有关系呢?

sadhen

sadhen      5 小时 31 分钟前

@est 看得很透彻!

c6h6benzene

c6h6benzene      5 小时 23 分钟前 via iPhone

我觉得这 SQL 也不是太复杂啊,LEFT JOIN 的那个子查询可写可不写,反正也注掉了。你说真正有逻辑的部分就只有 WHERE 的那个 in 了吧,这也不难啊。

xy90321

xy90321      4 小时 50 分钟前 via iPhone

稍微复杂点后台系统里,这种程度的 SQL 我们都是分给新人去开发测试的… 等你真看到的屎山一样十几张表揉在一起前前后后三四层左右结合内外连的时候再说吧… 而且一般这种屎山一样的 SQL ,换做程序实现更复杂…

Cbdy

Cbdy      4 小时 30 分钟前 via Android

两个有一个能跑就行(业界现状

night98

night98      4 小时 15 分钟前

@ikas 权限表这玩意完全没必要关联查。
1.数据量小,稍微有点要求的开发都会直接加载到内存
2.关联性弱,除了 user 和 role 的关联表数据量较大需要放到数据库查,其他的都可以直接走缓存查

综上所述你和楼主贴出来的 sql 都一般般

night98

night98      4 小时 11 分钟前

给楼主提个建议,要么跑,要么当 leader 禁止此类写法,否则都是打工的,没必要提这个,有心思写好代码的同事,你不说他也会改,没心思的你说了反而得罪人家,要么赶紧跑路

Elietio

Elietio      3 小时 49 分钟前

这算啥,我这一堆一二百行的 SQL ,需求整天变来变去,反反复复改了 N 次

chineselittleboy

chineselittleboy      3 小时 39 分钟前 via Android

能不能贴一下实现同样逻辑的代码

movieatravelove

movieatravelove      3 小时 24 分钟前 via Android

互联网公司和传统 IT 公司的做法本身就是不同的,场景不一样,互相觉得对方是傻 x 倒也很正常

IvanLi127

IvanLi127      2 小时 53 分钟前 via Android

你的示例,看起来问题不大

levelworm

levelworm      2 小时 2 分钟前

@leafre 这个问题是数据库设计的问题了。这么多 join 是查什么呢?好奇。

wangritian

wangritian      1 小时 59 分钟前

以前看过有人吐槽教务系统的 sql ,鼠标滚轮滚坏了都拉不到底

wanacry

wanacry      1 小时 18 分钟前 via iPhone

楼主你这培训班水平就别来秀了

seanzxx

seanzxx      几秒前

@vibbow 单词都看得懂,合在一起完全看不懂,即使有中文的注释

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK