[求教] 阿里 Java 编程规范:避免使用 IN。 那这个业务场景不用 IN 还有什么好方案么?

2021-05-31 10:57:13 +08:00
 bubuXiaoqi

公司里面有 10W 个客户,员工 A 负责其中 2W 个客户。 (数据在用户库里面)

现在 员工 A 要查询 [自己负责的所有客户] 的实时交易明细。(数据在订单库里面,和用户库是两个实例)

目前的方案是查这 2W 的客户的 ID,然后在交易明细里面进行客户 IDS 的过滤。

但是这样 IN 的内容就特别大,而且可能还会变大。今天看到 JAVA 编程规范里面说避免使用 IN,那这样还有什么好办法么。

因为 员工看自己负责的客户的 账户、订单、交易、等业务表太多太多了。每个表目前都是 in ids 的方案。

6838 次点击
所在节点    MySQL
64 条回复
romisanic
2021-05-31 16:35:40 +08:00
记得之前跟同事聊,淘宝这种客户量极大的平台,几乎任何一样业务数据都会单独存一份,但是因为存储并不值钱,而且有些信息不是要求特别实时的,所以可以冗余存储。

这里可以在其他地方存一份索引,比如前边有同学说的 es,至于你说的不好分页,既然要用 es 了,我觉得你不如把分页的条件考虑进去,一块做到 es 里。
bubuXiaoqi
2021-05-31 17:34:02 +08:00
@romisanic 我感觉也确实是只能 聚合数据到 es 然后考虑到各种分页情况 字段都提前设计好了。 额外还有一个 es 数据和 mysql 数据的一致性成本
akira
2021-05-31 20:19:25 +08:00
现在有性能问题么,没有的话就不用管他
lldld
2021-05-31 20:49:31 +08:00
如果这个员工的需求是有意义的, 那么最好是弄个 job, 每天把全公司的交易明细都处理一遍, 分员工出报表, 不需要做数据库的 IN 查询.
makdon
2021-05-31 21:02:14 +08:00
把员工 A 的 id 作为交易明细的一个维度冗余进去呗?
然后就可以 select * from order where manager=员工 A
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#%'
xuanbg
2021-05-31 21:15:53 +08:00
这个需求不是一个简单查询能做得好的。就别去想什么 in/join 或者 es 什么的了,根本不解决问题好吧。

客户经理查询 2w 客户的交易明细是不可能的事情,我能查得出,他也看不了。所以在没有具体需求的情况下,就不深入了。
xiaomingVTEX
2021-05-31 22:00:53 +08:00
这个可不可以加一张表用来存交易 + 员工呢
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.
arvinsilm
2021-06-01 08:37:31 +08:00
考虑出一张标签+明细的关联表吧,员工直接和明细对应不是好的解决方案
bthulu
2021-06-01 08:46:42 +08:00
你 in 试一试, 能满足业务需求就 in, 不要拘泥于什么规范, 规范时死的, 人时活的
timethinker
2021-06-01 09:22:48 +08:00
好吧,又是一个没有贴出具体 [数据库以及版本] 的问题。

使用 IN 语句在新版本的 MySQL 中是没问题的,加好索引就行,唯一的问题就是如果 IN 太多的值,可能会导致数据包超过 max_allowed_packet 设定的值。

如果你的心里存在怀疑,那么最好的办法应该在自己的数据库上好好测试一下,看看是否真的存在性能问题。如果你想我们帮你测试,那么至少要列出数据库以及它的版本,更详细的可以列举到数据量、索引是否建立、硬件环境等信息。

我觉得现在很多关于数据库的使用说法有点偏中医理论了,这不能用那不能用,很多时候这些问题都是出现在特定数据库的特定版本。人云亦云,迷信上个世纪的偏方和奇技淫巧,殊不知那些东西早就已经发生了变化。
qiumaoyuan
2021-06-01 10:12:34 +08:00
@qwe520liao 然后流传出来出现人传人的现象,大家还纷纷以为得到了真理。
qiumaoyuan
2021-06-01 10:16:28 +08:00
其实在我看来很多公司这种所谓的规范,就是为了某些人嘴上说的“软件工程的目的就是让低水平的人也能干活”,让大家不需要思考就能做事,造成的结果就是愚化员工,推动了视具体情况而选择工具和方法的能力。软件开发本没有那么多条条框框。
qiumaoyuan
2021-06-01 10:16:50 +08:00
推动了视具体情况而选择工具和方法的能力 -> 失去了视具体情况而选择工具和方法的能力
THESDZ
2021-06-01 10:29:24 +08:00
既然是根据交易流水来的,不如使用 mq 做预处理.
timethinker
2021-06-01 11:50:18 +08:00
@qiumaoyuan 规范的最终目的是服务于团队的,也就意味着想要提升整个团队的工作效率,就像代码是给人看的而不是给机器看的。进一步落地的方案可能是统一命名风格、禁用某些特性。时代在进步,同样我们使用的数据库或者其他中间件也在不断的改进和优化,但是很多方案却止步不前。开放学习和进步的团队文化是至关重要的,在我看来,现在很多的规范都已经过时了,也许在那个时候确实是有理由这样做,但是发展到现在就有点像用明朝的剑斩清朝的官。

反映出来的现象就是,由于很多人学习了这些早期项目的编码实践,后来又被其他人给继承,我不知道他们有没有仔细想过这些细节,但是科学的方法是进一步测试,得出实实在在的证据表明这些实践是否仍然有效。试图发现和总结出现这些现象的原因是另一个问题。

回到主题,对于楼主这个问题,我认为不在于 IN 本身是否好坏,而在于你的业务场景是否适合使用 IN,在 OLTP 场景,响应时间是至关重要的,同时也要保证数据的一致性和完整性,解决思路就是在时间和空间之间取得一个平衡。

对于下单来说,大多数系统需要保证操作及时响应,这也就意味着你不能进行太多耗时的操作(大部分时间花在了 IO 上),但是对于查询来讲,实时性也许就不那么强,或许可以通过异步的方式产生派生数据(即根据订单数据生成另一份数据),这一部分数据可以专门优化为方便查询的结构。当然是否采取这种方法取决于楼主业务的实际使用场景以及我方才这些假设是否成立。
qiumaoyuan
2021-06-01 13:39:18 +08:00
@qwe520liao 我觉得你把 52 楼的最后一句话又重复说了好几次,写成了四段话……其实有些东西只要是遇到过、思考过,从别人一句很凝练的话里就可以明白对方的意思并且认同。我们是没有分歧的。
timethinker
2021-06-01 17:29:34 +08:00
@qiumaoyuan 没有分歧,我只是想回复你一下,然后分享一些关于这件事情的一些想法,前面两段内容是我的一些看法。后面两段也算是具体回复一下关于这个帖子的一些解决思路。
opengps
2021-06-01 19:29:53 +08:00
能用 in 实现的,往往可以轻松把原本 in 的字段作为左表进行表连接,我最近刚有过一个这样的功能体验过,一分钟查不出来的改成 leftjoin 不到一秒钟就拿到了

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

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

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

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

© 2021 V2EX