老生常谈 关于 子查询的应用

4 天前
 wuhao1

select uid,(select wechat from member_a where tuid=m.tuid)wechat, (select name from admin_user where id =(select opuid from link where id=ldid))fzr ,no,ctime,(select ctime from member where id=uid)uctime, ldid,adid,rmb,(select count(id) from money_o where uid=m.uid and ctime < m.ctime)readin, (select count(id) from money_o where uid=m.uid and ctime > m.ctime)readout from money m where
ldid in(select id from link where qd=666 and ctime>$tms) and status=1 and ctime>=$czs having ctime> uctime and (ctime-uctime<480);

在后端程序中少不了要和 sql 接触,一部分人对子查询很抗拒认为 把很多逻辑都隐藏到 sql 中了不利于程序的可读性,然而 你同意吗?
上述 sql 使用了很多子查询,查询效率也并不会低,不过肯定可以省很多代码,因为很多数据如果不用子查询,那么就要多次链接数据库去做查询,然后组合数据。
愚见:适当的使用子查询其实是会更高效的!

1462 次点击
所在节点    MySQL
15 条回复
WashFreshFresh
4 天前
用 jpa 的时候基本都是单表查询,用 mybatis 的时候为了偷懒少写 sql 就 sql 一把梭了,因为不想写多个 xml ;我的体验是,sql 写的少代码写的多除了增强代码可读性,还能增强记忆,业务会记得比较清楚; sql 一把梭的真的今天写完明天就忘记业务细节了。
ldx78203199
4 天前
业务上谁写这种 sql ,直接开喷, 优化+维护成本太高,如果业务场景真有这么高建议上 ES
liangdi
4 天前
我一直做 toB 的系统,所以肯定是代码逻辑优先,基本不会这么用,要么是 db 自己做视图
sagaxu
4 天前
管理后台读从库,子查询,多表连随便造。但在非管理后台,使用较复杂的子查询或多表相连,有两个很纠结的点

1. 缓存机制不好设计,复杂程度远超单表查询
2. DB 采样统计失真,查询计划选择了错误的索引可能炸库
encounter2017
4 天前
我觉得还是看业务场景,比如说我这里有一个业务场景就是需要查询树状结点下面的所有子节点信息,这种情况下用 recursive cte 查询就很方便,一次就能查完,IO 都在数据库做了,不然的话还得多次查询数据库.

一个简单的示例
```
CREATE TABLE binary_tree (
id INT PRIMARY KEY,
value VARCHAR(255),
parent_id INT,
FOREIGN KEY (parent_id) REFERENCES binary_tree(id)
);

INSERT INTO binary_tree (id, value, parent_id) VALUES
(1, 'Root', NULL),
(2, 'Left Child', 1),
(3, 'Right Child', 1),
(4, 'Left Grandchild', 2),
(5, 'Right Grandchild', 2),
(6, 'Another Left Grandchild', 3),
(7, 'Another Right Grandchild', 3);

WITH RECURSIVE tree_cte AS (
-- Base case: select the root node
SELECT id, value, parent_id, 0 AS level, CAST(id AS text) AS path
FROM binary_tree
WHERE parent_id IS NULL

UNION ALL

-- Recursive case: select child nodes
SELECT c.id, c.value, c.parent_id, p.level + 1, CONCAT(p.path, ',', CAST(c.id AS text))
FROM binary_tree c
JOIN tree_cte p ON c.parent_id = p.id
)
SELECT id, value, parent_id, level, path
FROM tree_cte
ORDER BY path;

1,Root,,0,1
2,Left Child,1,1,"1,2"
4,Left Grandchild,2,2,"1,2,4"
5,Right Grandchild,2,2,"1,2,5"
3,Right Child,1,1,"1,3"
6,Another Left Grandchild,3,2,"1,3,6"
7,Another Right Grandchild,3,2,"1,3,7"

```
WIN2333
4 天前
这种确实适合代码逻辑,因为一眼就知道干了啥,sql 有心智负担。更值得讨论的是 join ,总有人跳出来说 join 怎么怎么不好,巴拉巴拉,有些一条 sql join 一下干出来的非得用代码实现。。。。
cccvno1
4 天前
任何一个子查询的表数据出了问题,这个查询直接就废了
wuhao1
4 天前
来分析下 如果没有用子查询 或者 连接查询 join
某些情况 join 比子查询可能效率更高
select uid,

(select wechat from member_a where tuid=m.tuid)wechat,

(select name from admin_user where id =(select opuid from link where id=ldid))fzr

,no,ctime,

(select ctime from member where id=uid)uctime,

ldid,adid,rmb,

(select count(id) from money_o where uid=m.uid and ctime < m.ctime)readin,

(select count(id) from money_o where uid=m.uid and ctime > m.ctime)readout

from money m where

ldid in(select id from link where qd=666 and ctime>$tms) and status=1 and ctime>=$czs having ctime> uctime and (ctime-uctime<480);

如果采用 程序 来集合数据那么可能组要查询 4 次左右 再把数据组合 效率上是否没有一次查询高?

@cccvno1 如果就按程序逻辑来组合数据其实也是一样的,如果其中一个子查询有异常 修复这个异常就好了
@encounter2017 确实某些场景下 子查询或者 join 可能会更高效
@sagaxu 同意,复杂的需求 往往在管理后台。
@ldx78203199 sql 也可以写注释的
@liangdi 某些人可能连视图也不会让你用, 因为也隐藏了一些逻辑,降低了可读性。
@WashFreshFresh 子查询 和 分开查 SQL 并不少
8355
4 天前
只能接受 where 条件用子查询,类似 in 的范围比较大或者查询条件在子查询表中。
这种 sql 完全无法优化,部分小表或着纯粹的关联查询在数据组装中批量查询可以直接读缓存,这么看起来真的是糟糕的不得了。。。
ldx78203199
4 天前
我觉得还是要定一个业务场景的背景,不然这种问题是不会有绝对答案,都会说出各自的道理。目前我所在的厂 这种业务代码 CR 不可能+2 过得了
ZZ74
4 天前
我无所谓
SQL 也是一种编程语言,大部分场景下 可以用 sql (存储过程),也可以用常见的编程语言+sql 实现。效率上也没多大区别。
wxf666
4 天前
@ldx78203199 #2

所以数据库的推荐用法,只能是当成 KV 数据库,得到数据后,再手动组装?



@sagaxu #4

不缓存应该也没事吧?

现在千元消费级固态,都能做到 100W 随机读写 / 秒( 4200 x 1024 / 4 = 107.5W ),

换句话说,数据库就算不用内存缓存,读写数据全走固态 IO ,应该也能做到几十万并发?

是这样算吗?



ldx78203199
4 天前
1. 你没经历过高并发 体会不到,这里面相关资料往上很多
2. 上面少说了一点,复杂度在业务代码中计算的成本是最低的,到数据库在运算成本是非常大
3. 可以举个最简单例子:假设你的 sql 一个语句是 1m ,不考虑 CPU 、内存、网络以及数据库的查询复杂度和缓存命中率等因素,SSD 的读写速度是 1000 MB/s ,每秒最多可以处理 1000 MB / 1 MB = 1000 次 I/O 。
sagaxu
4 天前
@wxf666

1. 关系型 DB 不光有 IO 开销,它要解析 SQL ,要制定查询计划,这些都会耗费 CPU
2. throughput 和 latency 是不同维度的东西,再快的 SSD latency 也在 10us 级,比内存慢 100 倍

并发数上去之后,最长响应时间,MySQL 比 Redis 高一到两个数量级
RandomJoke
3 天前
case by case ,没有所谓的银弹。对于团队而言,sql 太过复杂就是有些影响阅读和理解业务,性能这种东西毕竟看场景,在业务上符合就行。反而阅读和团队维护更重要吧

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

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

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

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

© 2021 V2EX