假设有一个 user 表,{id,name,phone},要根据名字(可能会传很多个)查询 user 的 id 和 phone,一次性查询全部然后转换成{name,user}的 map 匹配好还是每次都去查一次数据库然后 where name = xxx 好?
是否存在一个大概的数量值,来作为这两种方式的分界线?
1
ipwx 2021-08-29 00:36:39 +08:00 1
前一个没看懂。
标准操作我觉得是建个临时表,把想差的名字都写进去,然后用 JOIN 。 |
2
ipwx 2021-08-29 00:37:24 +08:00
ps 临时表是 connection-only in-memory 的
|
3
ravelminerva 2021-08-29 00:42:55 +08:00
我觉得你可以做一个测试。
|
4
Co1a 2021-08-29 00:47:36 +08:00 via iPhone 1
终于遇到个能答上来的问题了
具体得看你说的 “好”怎么定义 “空间好”:那当然是直接去数据库查 “时间好”:缓存到应用里?或者外部应用做缓存? 比较“好”的做法是对 user 表做缓存,一旦对用户表做了任何 crud 操作,删除相对应的键重新插入,空档期缓存没命中再走 SQL DB,不过得具体情况具体分析。 之前做的 OA 也有这个问题,子部门多父部门广,树状表结构走 Oracle 在测试环境下面奇慢无比,上面不让用 Redis,没办法,只能把对应权限的数据写进 session 里,登陆给他存一下,好在用户量不多,还能撑住。 |
5
CEBBCAT 2021-08-29 00:50:36 +08:00
不能保证 user 的 name 唯一,所以建议按照模糊查询的方式做:WHERE name IN ('alice', 'bob')
|
6
Amber2011 OP @ipwx 第一个就是直接查全表,然后把结果转换为 Map(代码层面),key 是 name,value 是对象. 然后去判断这个 map 里是否存在指定的 name.
第二种就是传入多少个 name 就查多少次 一开始写的第一种,然后被吐槽说如果查出来的数据量太大(同时需要查询的量不算多)还不如一个一个查 |
8
fkdog 2021-08-29 03:40:54 +08:00
当然是能一次取完的就不要取 N 次了。
for 循环难道就能节省数据量了?你同事吐槽你他自己也是个半桶水。 |
9
opengps 2021-08-29 10:07:54 +08:00
取决于业务要求:
一次取大量数据用的 in 的写法是很不利与索引的,单好处是可能只有一次 io 。 逐条取很多次数据好处往往是索引到位。单个获取很快,但是缺点也很明显就是 io 次数明显太多了。 建议做成分页类的逻辑 |
10
BiteTheDust 2021-08-29 11:45:48 +08:00
一次查询多个能省 IO 索引的话看具体情况了 还是有机会能命中一些的
|
11
ipwx 2021-08-29 15:07:44 +08:00
@Amber2011 你没理解我说的。
你这个问题没说清楚的一个点是,假设表里有 N 个用户,你每次要查的用户数量 k,到底是远小于 N 还是等于 N ? 如果 1 < k << N,那么就用临时表存储你要查的用户名,然后用 JOIN 从主表得到所有需要的结果。 |
12
ipwx 2021-08-29 15:08:48 +08:00 1
哦顺便如果只是三五个那写个 IN 就行了。
子表说的是 30 50 乃至 300 500 个要查的用户名,但是总表可能有 30 50 万个用户这种情况。 |
13
LearnFeedback 2021-08-30 10:35:40 +08:00
1 、前一种情况实际上是做了本地的缓存
|
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 级接口且有性能诉求不要进行上述优化。。。
|