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
Amber2011
V2EX  ›  MySQL

一次查询 n 条数据和查询一条数据重复 n 次的区别和影响?

  •  
  •   Amber2011 · 2021-08-29 00:24:52 +08:00 via Android · 3061 次点击
    这是一个创建于 1178 天前的主题,其中的信息可能已经有所发展或是发生改变。

    假设有一个 user 表,{id,name,phone},要根据名字(可能会传很多个)查询 user 的 id 和 phone,一次性查询全部然后转换成{name,user}的 map 匹配好还是每次都去查一次数据库然后 where name = xxx 好?

    是否存在一个大概的数量值,来作为这两种方式的分界线?

    14 条回复    2021-09-16 19:45:48 +08:00
    ipwx
        1
    ipwx  
       2021-08-29 00:36:39 +08:00   ❤️ 1
    前一个没看懂。

    标准操作我觉得是建个临时表,把想差的名字都写进去,然后用 JOIN 。
    ipwx
        2
    ipwx  
       2021-08-29 00:37:24 +08:00
    ps 临时表是 connection-only in-memory 的
    ravelminerva
        3
    ravelminerva  
       2021-08-29 00:42:55 +08:00
    我觉得你可以做一个测试。
    Co1a
        4
    Co1a  
       2021-08-29 00:47:36 +08:00 via iPhone   ❤️ 1
    终于遇到个能答上来的问题了

    具体得看你说的 “好”怎么定义
    “空间好”:那当然是直接去数据库查
    “时间好”:缓存到应用里?或者外部应用做缓存?

    比较“好”的做法是对 user 表做缓存,一旦对用户表做了任何 crud 操作,删除相对应的键重新插入,空档期缓存没命中再走 SQL DB,不过得具体情况具体分析。

    之前做的 OA 也有这个问题,子部门多父部门广,树状表结构走 Oracle 在测试环境下面奇慢无比,上面不让用 Redis,没办法,只能把对应权限的数据写进 session 里,登陆给他存一下,好在用户量不多,还能撑住。
    CEBBCAT
        5
    CEBBCAT  
       2021-08-29 00:50:36 +08:00
    不能保证 user 的 name 唯一,所以建议按照模糊查询的方式做:WHERE name IN ('alice', 'bob')
    Amber2011
        6
    Amber2011  
    OP
       2021-08-29 00:51:20 +08:00
    @ipwx 第一个就是直接查全表,然后把结果转换为 Map(代码层面),key 是 name,value 是对象. 然后去判断这个 map 里是否存在指定的 name.
    第二种就是传入多少个 name 就查多少次
    一开始写的第一种,然后被吐槽说如果查出来的数据量太大(同时需要查询的量不算多)还不如一个一个查
    Hurriance
        7
    Hurriance  
       2021-08-29 00:56:54 +08:00
    @Amber2011 第一种做法即可吧,我不太理解,是不是无论怎么样都需要找到同样的记录呢
    fkdog
        8
    fkdog  
       2021-08-29 03:40:54 +08:00
    当然是能一次取完的就不要取 N 次了。
    for 循环难道就能节省数据量了?你同事吐槽你他自己也是个半桶水。
    opengps
        9
    opengps  
       2021-08-29 10:07:54 +08:00
    取决于业务要求:
    一次取大量数据用的 in 的写法是很不利与索引的,单好处是可能只有一次 io 。
    逐条取很多次数据好处往往是索引到位。单个获取很快,但是缺点也很明显就是 io 次数明显太多了。
    建议做成分页类的逻辑
    BiteTheDust
        10
    BiteTheDust  
       2021-08-29 11:45:48 +08:00
    一次查询多个能省 IO 索引的话看具体情况了 还是有机会能命中一些的
    ipwx
        11
    ipwx  
       2021-08-29 15:07:44 +08:00
    @Amber2011 你没理解我说的。

    你这个问题没说清楚的一个点是,假设表里有 N 个用户,你每次要查的用户数量 k,到底是远小于 N 还是等于 N ?

    如果 1 < k << N,那么就用临时表存储你要查的用户名,然后用 JOIN 从主表得到所有需要的结果。
    ipwx
        12
    ipwx  
       2021-08-29 15:08:48 +08:00   ❤️ 1
    哦顺便如果只是三五个那写个 IN 就行了。

    子表说的是 30 50 乃至 300 500 个要查的用户名,但是总表可能有 30 50 万个用户这种情况。
    LearnFeedback
        13
    LearnFeedback  
       2021-08-30 10:35:40 +08:00
    1 、前一种情况实际上是做了本地的缓存
    Aresxue
        14
    Aresxue  
       2021-09-16 19:45:48 +08:00
    要看预估数据量喽,第一种 in 在 name 超大的情况下会造成 sql 语句超过 max_allowed_packet, 而且不利于做缓存优化,还有可能因为单次数据量过大撑爆,第二种就是单次连接只查一条数据过于浪费,可以折中一下, 分析下 name 的 Cardinality, 然后一批 name 过来将其拆分为几个小集合,单个集合按照 cardinality 的预估最终维持查出的数据量单次在指定大小(如 1000)左右,然后在内存里拼接数据, select 语句的开销除了 query 还有 fetch 和 transport, 多线程去做一批的查询最后汇总一般比大结果集单次查询会快上一些。最后说一句如果不是 p0 级接口且有性能诉求不要进行上述优化。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5379 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 08:45 · PVG 16:45 · LAX 00:45 · JFK 03:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.