逻辑大量的写在 sql 语句里

2022-02-21 16:40:54 +08:00
 moxiaowei

今天看了下同事写的代码,才发现他居然喜欢把大量的逻辑写在 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 的也很多。
18736 次点击
所在节点    Java
244 条回复
F281M6Dh8DXpD1g2
2022-02-22 13:35:06 +08:00
@msg7086
"但是应用服务器做横向扩展却很简单,堆一打机器,对着数据库干就是了,几乎是零惩罚的。
(比如堆 100 台机器就能有近乎 100 倍的性能。)"
无非不过是放弃了数据库的一致性保证而已
你要自己写 code 能做到跟数据库一样的一致性保证的话肯定跑不过数据库。
onionKnight888
2022-02-22 13:35:20 +08:00
oracle 上跑这点 sql 完全不是问题
moxiaowei
2022-02-22 13:35:40 +08:00
@buermo 就你会,不用震惊的 ,反正我是菜鸡了, 我躺平了。
onionKnight888
2022-02-22 13:37:48 +08:00
@raptor 改以前的存储过程真是 tm 痛苦,sql 相对而言简单多了
Braisdom
2022-02-22 13:38:12 +08:00
建议你看一下: https://github.com/braisdom/ObjectiveSql
一种比较优雅的方式写 SQL
guabimian
2022-02-22 13:46:57 +08:00
这种配置表 简单联合查询 有什么问题? 分开几个循环去处理比较优雅?
不要拿关系数据库当 kv 来用好吧
msg7086
2022-02-22 13:53:29 +08:00
@liprais 对,无非是让数据库保证一致性,还是自己重新发明一遍一致性的问题。
对于大多数应用来说,会话之间不需要保证一致性,所以靠多开应用服务器(以及在单台机器上多开线程和进程)来提升运行速度。
如果有特殊需要,那当然特殊处理,所以银行、电信那些项目都有他们自己的特殊癖好,弄个大机,搞个 Oracle 之类的扛着,这个就不多说了。
FlyingShark
2022-02-22 13:55:17 +08:00
@danhahaha 楼主自找的啦,34 楼就开炮了,我看得笑死
cocong
2022-02-22 13:56:21 +08:00
没被坑过是体会不到这种痛的,例子里几十行 sql 还好,你们是没见过上千行的 sql ,动不动就死锁,一天到晚的出故障。
msg7086
2022-02-22 13:56:54 +08:00
@guabimian 拿楼主这个例子来说,子查询是可以拿出来单独跑的。
跑出 rm.menu_id list 以后,再做一个 m.id in (#{list})。
前者因为可以做查询缓存或者应用层缓存,只要 role 表不经常改变的话,可以减少很多无谓的查询。
xlzyxxn
2022-02-22 14:04:04 +08:00
@Jihua 耗什么时?耗你的时还是机器的时
28Sv0ngQfIE7Yloe
2022-02-22 14:04:55 +08:00
示例没啥问题吧,也没看到太多逻辑啊
guabimian
2022-02-22 14:08:24 +08:00
@msg7086 看他表名就知道没几行数据 还考虑各种缓存。过度设计考虑真是没必要 具体情况具体分析吧。不要把 mysql 想太弱鸡啦。另外很多脚本语言都特别怕循环,数据拿出来处理如果不用 pandas 这种 lib 大多数会很慢不会比数据库快。

总之还是要具体情况具体分析 ,教条主义要不得,没有万能药。
wangsd
2022-02-22 14:09:02 +08:00
你得看实际场景,不能一棍子打死,EPR 、工业领域这些领域写这种 SQL 很常见,很多 SQL 写好了以后基本不会去做改动。
aitaii
2022-02-22 14:11:22 +08:00
我写可以,其他同事不能这么写,我怎么维护。(:dog
clf
2022-02-22 14:12:30 +08:00
曾经还有全都写存储过程来实现业务逻辑的,项目基础代码就是调用存储过程去 CRUD 。
liangch
2022-02-22 14:13:34 +08:00
示例的 sql 算简单的了,没啥复杂的。
NeezerGu
2022-02-22 14:16:21 +08:00
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}

---
这块是我不懂 sql 了吗?
rm left join r ,然后无论是 where 里还是 select 里都没有用到 r 的内容
如果不考虑重复产生的笛卡尔积,那这个 left join 有什么意义吗?
unregister
2022-02-22 14:35:01 +08:00
以前搞 BI ,整天写 SQL,真的写到吐。我觉得 sql 复杂的话可读性不是很好,关联查询不要超过三张表,而且有些高级函数不同的数据库不一样。
l00t
2022-02-22 14:39:39 +08:00
@NeezerGu 在第二个 left join 里有用到。 当然它的这两个 left join 多半是 join 的误用,写成这样说明这人的 SQL 功底也不太行。

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

https://www.v2ex.com/t/835439

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

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

© 2021 V2EX