公司里面有 10W 个客户,员工 A 负责其中 2W 个客户。 (数据在用户库里面)
现在 员工 A 要查询 [自己负责的所有客户] 的实时交易明细。(数据在订单库里面,和用户库是两个实例)
目前的方案是查这 2W 的客户的 ID,然后在交易明细里面进行客户 IDS 的过滤。
但是这样 IN 的内容就特别大,而且可能还会变大。今天看到 JAVA 编程规范里面说避免使用 IN,那这样还有什么好办法么。
因为 员工看自己负责的客户的 账户、订单、交易、等业务表太多太多了。每个表目前都是 in ids 的方案。
1
BBCCBB 2021-05-31 10:58:17 +08:00
看能不能改成 join.
|
2
bubuXiaoqi OP @BBCCBB 因为在不同的数据库实例里面了。所以没有办法用 join
|
3
bubuXiaoqi OP 用户、订单、商品 等都是单独部署的服务器和数据库
|
4
statement 2021-05-31 11:03:09 +08:00
mysql 最大 1000 。oracle 最大 5000 如果 sql 不知道怎么写。 就分批 in
|
5
buster 2021-05-31 11:04:42 +08:00
DBLINK 这种方案呢
|
6
clf 2021-05-31 11:13:24 +08:00
试着跨数据库 join ?只要几个数据库的类型是一致的,各家都有跨服务器数据库查询的方法。
还有就是所有表都存一个负责人的 id 。 |
7
eason1874 2021-05-31 11:14:44 +08:00
可以考虑楼上说的 DBLink
但如果是我,有可能的话,我直接在订单库维护一个客户关系表,反正占不了多少空间 |
8
Jooooooooo 2021-05-31 11:15:53 +08:00
in 特别多 mysql 踩不上索引, 200 个差不多是极限了.
|
9
bubuXiaoqi OP @lychs1998 主要数据量也非常大。 哪怕都在同一个数据库 in 太多了用不上索引速度都很慢
|
10
bubuXiaoqi OP @lychs1998 员工和客户的关系是会变的 而且一个客户可能会被多个员工负责。。。 就是员工负责 部分标签的客户。 所以不同的员工可能都会负责同一个标签
|
11
bubuXiaoqi OP @Jooooooooo 对 所以现在很头疼
|
12
bubuXiaoqi OP @eason1874 这个方案还是要进行数据库的关联过滤么。 但是大表关联大表 之前没有拆之前就是关联查询的 效果好差。
|
13
bubuXiaoqi OP @statement 分批 in 的话 不仅数据要进行汇合 。而且面对过滤分页的场景处理不了。
|
14
bubuXiaoqi OP @buster 最早的时候所有数据库都在一起的时候。效率都挺差的 因为数据挺多的。 除非针对每个 SQL 针对性的给索引 不然大表间关联 之前用的也很慢
|
15
biuaxia 2021-05-31 11:31:46 +08:00
同问,先关注一波。有好的回复麻烦 call 一下。
@bubuXiaoqi |
16
bubuXiaoqi OP @biuaxia 1
|
17
bubuXiaoqi OP @Jooooooooo 有一个参数可以改 in 的内容的值。我目前改的不小。但是这个方案本身好像不长久。而且性能也不行
|
18
xwayway 2021-05-31 11:38:04 +08:00
总共 10w 客户,一个员工就 2w 了。这么厉害。2w 客户,感觉员工要忙死
|
19
dswyzx 2021-05-31 11:43:20 +08:00
ids 临时表然后 join or exists
|
20
Jooooooooo 2021-05-31 11:45:35 +08:00
|
21
bubuXiaoqi OP @Jooooooooo 你的意思 最合适的还是关联表查询过滤么
|
22
wfd0807 2021-05-31 11:49:20 +08:00
换一个思路,楼主描述的“ 员工 A 要查询 [自己负责的所有客户] 的实时交易明细”,这个需求真的没有问题吗?
实时交易明细,是全部的交易明细吗?如果是的话,批量查询 2w 用户的全部交易明细的目的是啥呢?就算给员工 A 实现了这种查询,你确定有意义吗?我敢打保票,他会在点查询按钮之前,先筛选用户 |
23
bubuXiaoqi OP @wfd0807 比如说 我要看我今天所有客户产生的明细或者明细的报表 ,这个时候我只有时间段的 不会针对到具体的客户的
|
24
buster 2021-05-31 12:02:47 +08:00
如果现在 in ids 的代码还可以支撑运行,那完全可以考虑把所有的表都放在一个库里,之后使用 join 来解决 in ids 的问题,之后再考虑优化查询效率(逻辑、索引、分库分表)
|
25
wfd0807 2021-05-31 12:15:06 +08:00
@bubuXiaoqi 所以,你这个需求的真相是想查看再加工数据和报表,这应该通过 BI 手段是实现
|
26
wfd0807 2021-05-31 12:21:51 +08:00
@bubuXiaoqi ps,目前的分库方案没看出来有什么实际应用上的优势,如果不分库的话,楼上都说明了,join 可以解决 in ids 的问题,慢就优化,就算优化需要分库分表了,也不应该是现在这种分
|
27
jorneyr 2021-05-31 12:56:59 +08:00
冗余列存储关系
|
28
admol 2021-05-31 13:13:11 +08:00
交易明细里面记录下员工 A 的 Id ?
|
29
clf 2021-05-31 13:22:04 +08:00 1
其实感觉就是你们的业务数据存储的方式(数据结构)出了问题。另外就是分库分的看上去像徒增成本。跨服务器间查询会有连接成本的。
你们用户标签估计是用逗号分隔丢在一个字段里的?也不知道员工会不会负责多个标签。 其实也可以考虑引入 Elaticsearch,存进 Mysql 的数据都同步进去,员工搜索用户信息的时候放在 ES 里进行。 |
30
yitingbai 2021-05-31 13:26:45 +08:00
我也为这个问题头疼, 似乎没有比 in 更好的方法, 因为 in 太好用了
|
31
lidashuang 2021-05-31 13:52:19 +08:00
redis set
|
32
geminius2333 2021-05-31 14:04:17 +08:00
收藏一波,看看大佬们的回复
|
33
bubuXiaoqi OP @lychs1998 员工 标签 和客户是三张表和两个映射表。 用 es 的话主要是设计的业务表太多了 都得弄一份 太麻烦了。。
|
34
TomVista 2021-05-31 14:18:17 +08:00
客户的标签可以修改吗? 是不是可以构建一个 员工-标签-订单的关系?
|
35
bubuXiaoqi OP @TomVista 客户的标签可以修改
|
36
zoharSoul 2021-05-31 14:31:55 +08:00
拉到 es 里面搜索, 搜到到 id 回 mysql 查
|
37
bubuXiaoqi OP @zoharSoul 如果业务重新设计的话 可能会这样做, 但是这样做不了分页。比如把 T1 表的数据放入 ES 了 ,业务有的需要进行 T1 T2 的关联过滤分页查询。就做不到了。
|
38
hmdsw 2021-05-31 15:01:53 +08:00
exists?
|
39
glacial 2021-05-31 15:14:45 +08:00
@bubuXiaoqi 建一张员工与客户的关联表, 到你订单库里,然后通过 消息中间件或 cdc 同步这张关联表
|
40
PiersSoCool 2021-05-31 15:52:31 +08:00
分批 in
话说这种数据肯定没有意义,这么多数据,能看得过来吗?一次看 2000 * 交易量的数据,怕不是真需求... |
41
romisanic 2021-05-31 16:35:40 +08:00
记得之前跟同事聊,淘宝这种客户量极大的平台,几乎任何一样业务数据都会单独存一份,但是因为存储并不值钱,而且有些信息不是要求特别实时的,所以可以冗余存储。
这里可以在其他地方存一份索引,比如前边有同学说的 es,至于你说的不好分页,既然要用 es 了,我觉得你不如把分页的条件考虑进去,一块做到 es 里。 |
42
bubuXiaoqi OP @romisanic 我感觉也确实是只能 聚合数据到 es 然后考虑到各种分页情况 字段都提前设计好了。 额外还有一个 es 数据和 mysql 数据的一致性成本
|
43
akira 2021-05-31 20:19:25 +08:00
现在有性能问题么,没有的话就不用管他
|
44
lldld 2021-05-31 20:49:31 +08:00
如果这个员工的需求是有意义的, 那么最好是弄个 job, 每天把全公司的交易明细都处理一遍, 分员工出报表, 不需要做数据库的 IN 查询.
|
45
makdon 2021-05-31 21:02:14 +08:00
把员工 A 的 id 作为交易明细的一个维度冗余进去呗?
然后就可以 select * from order where manager=员工 A |
46
lldld 2021-05-31 21:03:53 +08:00
"一个客户可能被多个员工负责而且会变。
所以没有办法存员工 id " 按说即使是多个员工负责, 也不会超过 10 个吧? 拼接多个员工 id 存在一个字段, 用 like 应该可以. 如果觉得效率低, 可以把员工 id 分组, 比如用 4 个字段存负责的销售 id: sales00, sales01, sales02, sales03, 按照 id%4 分别存储(hash 更好). sales00 => #100#,#104# sales01 => #101# sales02 => #1002#,#1006# sales03 => 现在查询员工 1002 的客户的明细: select * from trades where sales02 like '%#1002#%' |
47
xuanbg 2021-05-31 21:15:53 +08:00 1
这个需求不是一个简单查询能做得好的。就别去想什么 in/join 或者 es 什么的了,根本不解决问题好吧。
客户经理查询 2w 客户的交易明细是不可能的事情,我能查得出,他也看不了。所以在没有具体需求的情况下,就不深入了。 |
48
xiaomingVTEX 2021-05-31 22:00:53 +08:00
这个可不可以加一张表用来存交易 + 员工呢
|
49
cubecube 2021-06-01 00:22:13 +08:00
in 性能很差的,尤其是 in 里面如果有 null,貌似逻辑还有问题
> An in statement will be parsed identically to field=val1 or field=val2 or field=val3. Putting a null in there will boil down to field=null which won't work. |
50
arvinsilm 2021-06-01 08:37:31 +08:00
考虑出一张标签+明细的关联表吧,员工直接和明细对应不是好的解决方案
|
51
bthulu 2021-06-01 08:46:42 +08:00
你 in 试一试, 能满足业务需求就 in, 不要拘泥于什么规范, 规范时死的, 人时活的
|
52
timethinker 2021-06-01 09:22:48 +08:00 4
好吧,又是一个没有贴出具体 [数据库以及版本] 的问题。
使用 IN 语句在新版本的 MySQL 中是没问题的,加好索引就行,唯一的问题就是如果 IN 太多的值,可能会导致数据包超过 max_allowed_packet 设定的值。 如果你的心里存在怀疑,那么最好的办法应该在自己的数据库上好好测试一下,看看是否真的存在性能问题。如果你想我们帮你测试,那么至少要列出数据库以及它的版本,更详细的可以列举到数据量、索引是否建立、硬件环境等信息。 我觉得现在很多关于数据库的使用说法有点偏中医理论了,这不能用那不能用,很多时候这些问题都是出现在特定数据库的特定版本。人云亦云,迷信上个世纪的偏方和奇技淫巧,殊不知那些东西早就已经发生了变化。 |
53
qiumaoyuan 2021-06-01 10:12:34 +08:00
@qwe520liao 然后流传出来出现人传人的现象,大家还纷纷以为得到了真理。
|
54
qiumaoyuan 2021-06-01 10:16:28 +08:00
其实在我看来很多公司这种所谓的规范,就是为了某些人嘴上说的“软件工程的目的就是让低水平的人也能干活”,让大家不需要思考就能做事,造成的结果就是愚化员工,推动了视具体情况而选择工具和方法的能力。软件开发本没有那么多条条框框。
|
55
qiumaoyuan 2021-06-01 10:16:50 +08:00
推动了视具体情况而选择工具和方法的能力 -> 失去了视具体情况而选择工具和方法的能力
|
56
THESDZ 2021-06-01 10:29:24 +08:00
既然是根据交易流水来的,不如使用 mq 做预处理.
|
57
timethinker 2021-06-01 11:50:18 +08:00 1
@qiumaoyuan 规范的最终目的是服务于团队的,也就意味着想要提升整个团队的工作效率,就像代码是给人看的而不是给机器看的。进一步落地的方案可能是统一命名风格、禁用某些特性。时代在进步,同样我们使用的数据库或者其他中间件也在不断的改进和优化,但是很多方案却止步不前。开放学习和进步的团队文化是至关重要的,在我看来,现在很多的规范都已经过时了,也许在那个时候确实是有理由这样做,但是发展到现在就有点像用明朝的剑斩清朝的官。
反映出来的现象就是,由于很多人学习了这些早期项目的编码实践,后来又被其他人给继承,我不知道他们有没有仔细想过这些细节,但是科学的方法是进一步测试,得出实实在在的证据表明这些实践是否仍然有效。试图发现和总结出现这些现象的原因是另一个问题。 回到主题,对于楼主这个问题,我认为不在于 IN 本身是否好坏,而在于你的业务场景是否适合使用 IN,在 OLTP 场景,响应时间是至关重要的,同时也要保证数据的一致性和完整性,解决思路就是在时间和空间之间取得一个平衡。 对于下单来说,大多数系统需要保证操作及时响应,这也就意味着你不能进行太多耗时的操作(大部分时间花在了 IO 上),但是对于查询来讲,实时性也许就不那么强,或许可以通过异步的方式产生派生数据(即根据订单数据生成另一份数据),这一部分数据可以专门优化为方便查询的结构。当然是否采取这种方法取决于楼主业务的实际使用场景以及我方才这些假设是否成立。 |
58
qiumaoyuan 2021-06-01 13:39:18 +08:00
@qwe520liao 我觉得你把 52 楼的最后一句话又重复说了好几次,写成了四段话……其实有些东西只要是遇到过、思考过,从别人一句很凝练的话里就可以明白对方的意思并且认同。我们是没有分歧的。
|
59
timethinker 2021-06-01 17:29:34 +08:00
@qiumaoyuan 没有分歧,我只是想回复你一下,然后分享一些关于这件事情的一些想法,前面两段内容是我的一些看法。后面两段也算是具体回复一下关于这个帖子的一些解决思路。
|
60
opengps 2021-06-01 19:29:53 +08:00
能用 in 实现的,往往可以轻松把原本 in 的字段作为左表进行表连接,我最近刚有过一个这样的功能体验过,一分钟查不出来的改成 leftjoin 不到一秒钟就拿到了
|
61
myCupOfTea 2021-06-02 10:15:28 +08:00
@opengps 举个例子看看,有点没理解怎么转化的 QAQ
|
62
zhozho 2021-06-02 10:41:01 +08:00 via Android
不是,我是这么理解的哈,前端页面上分两步,先客户表查员工 A 负责的客户列表,然后员工想看哪个客户的交易明细单独 where 查就是了。
实际场景有一下看那么多客户交易的的嘛,想到一个导出,导出也不能全部导出吧。 我觉得避免 in,就先避免查所有 |
63
bubuXiaoqi OP @opengps 不用 join 第一是因为不在一个数据库实例 第二是因为 员工-标签-客户 已经是 4 5 个表的关联。这一块是可以缓存数据的。 全在数据库查的话 关联的就更多了 而且也看起来可读性很差。 实在要关联还得再单独维护一张员工->客户 IDS 的表。
|
64
QiangZai 2021-06-11 16:17:31 +08:00
不能利用 存储过程吗 ? 创建临时表 ?
|