V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MySQL 5.5 Community Server
MySQL 5.6 Community Server
Percona Configuration Wizard
XtraBackup 搭建主从复制
Great Sites on MySQL
Percona
MySQL Performance Blog
Severalnines
推荐管理工具
Sequel Pro
phpMyAdmin
推荐书目
MySQL Cookbook
MySQL 相关项目
MariaDB
Drizzle
参考文档
http://mysql-python.sourceforge.net/MySQLdb.html
wuhao1
V2EX  ›  MySQL

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

  •  1
     
  •   wuhao1 · 4 天前 · 1458 次点击

    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 使用了很多子查询,查询效率也并不会低,不过肯定可以省很多代码,因为很多数据如果不用子查询,那么就要多次链接数据库去做查询,然后组合数据。
    愚见:适当的使用子查询其实是会更高效的!

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

    1. 缓存机制不好设计,复杂程度远超单表查询
    2. DB 采样统计失真,查询计划选择了错误的索引可能炸库
    encounter2017
        5
    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
        6
    WIN2333  
       4 天前
    这种确实适合代码逻辑,因为一眼就知道干了啥,sql 有心智负担。更值得讨论的是 join ,总有人跳出来说 join 怎么怎么不好,巴拉巴拉,有些一条 sql join 一下干出来的非得用代码实现。。。。
    cccvno1
        7
    cccvno1  
       4 天前
    任何一个子查询的表数据出了问题,这个查询直接就废了
    wuhao1
        8
    wuhao1  
    OP
       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
        9
    8355  
       4 天前
    只能接受 where 条件用子查询,类似 in 的范围比较大或者查询条件在子查询表中。
    这种 sql 完全无法优化,部分小表或着纯粹的关联查询在数据组装中批量查询可以直接读缓存,这么看起来真的是糟糕的不得了。。。
    ldx78203199
        10
    ldx78203199  
       4 天前
    我觉得还是要定一个业务场景的背景,不然这种问题是不会有绝对答案,都会说出各自的道理。目前我所在的厂 这种业务代码 CR 不可能+2 过得了
    ZZ74
        11
    ZZ74  
       4 天前
    我无所谓
    SQL 也是一种编程语言,大部分场景下 可以用 sql (存储过程),也可以用常见的编程语言+sql 实现。效率上也没多大区别。
    wxf666
        12
    wxf666  
       4 天前
    @ldx78203199 #2

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



    @sagaxu #4

    不缓存应该也没事吧?

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

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

    是这样算吗?



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

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

    并发数上去之后,最长响应时间,MySQL 比 Redis 高一到两个数量级
    RandomJoke
        15
    RandomJoke  
       3 天前
    case by case ,没有所谓的银弹。对于团队而言,sql 太过复杂就是有些影响阅读和理解业务,性能这种东西毕竟看场景,在业务上符合就行。反而阅读和团队维护更重要吧
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1869 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 16:17 · PVG 00:17 · LAX 09:17 · JFK 12:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.