背景:开发一个新项目,一个前端、两个开发、一个项目经理。
刚开始开发大家也没啥矛盾,一个正经地开会、讨论、分配任务、各干各的活。开始大家还是比较愉快的,之后就发生了这个几件小事。
定义一个数据库的字段,用来表示这条记录的 type(类型)。整张表一开始都是本人定义的,开始就想定义成 varchar 类型的,在代码里面定义好枚举,然后愉快继续开发。到后来,被开发同事(以后用 C 指代)看到(因为这个时候要使用到这张表)之后。
C:"这个字段 type 改成 int 吧。"。
wo:"为啥?当时定义成 varchar,考虑到可读性好一点,如果 int,好处是节省空间嘛。不过,这张表记录不会超过几百个条记录,还是 varchar 好一点。"
C:"一般这个类型一般都是使用 int 类型的,你这样以后出了啥问题怎么办"
wo:"能有啥问题?"
C:"现在当然还看不出来,万一以后出了,这种都不好改。"
wo:"....."
最后还是没改。
另公司没有代码习惯数据库的定义的规范,而且公司一般用 varchar 来定义类型。
还是数据库的设计问题。用了随机生成的 uuid 做主键,被看到后,告诉 wo 要加一个自增 id。wo:"为啥?",C :"一般表都会有个自增的作为主键的。" wo:"表 1 表 2 会被表 3 引用到主键,所以表 1 表 2 的主键要唯一,自增不 符合。" C:"引用的时候用 uuid,但是自增 id 还是加一个吧。" wo:"..." 最后还是加了一个。
当然其实不止数据库了。还有,C 写的模块要有一个函数需要被 wo 调用。当开始写了一个传一个参数的,后来考 虑到可能有批量调用的场景。就又写了一个可以传 list 的接口。然后,就把之前那个给删了。wo:"别删啊, 留着呗。" C:"有 list 的就够了,干嘛要那个。。" wo:"好吧...."
之前也经常和别人合作写代码,虽然也有这种习惯、写法不一致的情况,但是发生的次数还是比较少。但这次,发生地是最频繁的了。有时候争执的时候妥协,有时候要据理力争。最近,也在烦恼,到底是为什么会这样?是 wo 的太固执,还是别人做法不对。最烦的时候,想想还是一个人开发的时候爽。安静下来想想,如果合作的好,还能从别人身上吸收到不少好处。也许一种相对来说好的方式来解决各自觉得有道理的情况是不是 "自己的模块怎么实现的尽量按自己的思路来,别人怎么实现的也别去管"。
当然虽然合作的不愉快,不过写代码的人都是善良的。
深知自己所知甚浅,很想得到各位大佬一路走来的经验分享,能有自己的心路历程就更好了。
1
liuhuansir 2018-06-02 12:25:38 +08:00 2
最后一个不说,1,2 这两个感觉他的说法是对的
|
2
canrom7 2018-06-02 12:31:42 +08:00
恕我直言别人的比你的正确
|
3
hduwillsky 2018-06-02 12:32:17 +08:00
一般主键是与业务无关的,防止传递依赖。同上楼,感觉 1、2 C 说的没毛病
|
4
duanquanyong 2018-06-02 12:36:27 +08:00
@hduwillsky 如果做主主复制,双活的时候,UUID 还是比较爽的
|
5
broadliyn 2018-06-02 12:45:58 +08:00 5
楼主应该是那种水平一般,但是又觉得自己很厉害的人。
所以不要扯到理念问题,先把自己的水桶装满再来晃。 |
6
huluhulu 2018-06-02 12:52:44 +08:00 via iPhone
我决定他比你正确……多学学一些规范性的基础吧
|
7
lxml 2018-06-02 12:54:02 +08:00 via Android 1
我怎么觉得应该发帖的是 c,int 和 vchar 用来表示类型问题不大,这个东西反正都是代码里写枚举或者 const 的,不存在可读性哪个更好的问题,个人觉得 int 更佳。
第二个 uuid 本来就有重复的可能,而且用 uuid 做主键,主键排序和遍历一定不如自增的用起来方便,这显然是常识。 第三个,没兼容性包袱,在开发阶段尽量精简代码,甩掉没用的接口或函数我觉得没啥问题吧。 |
8
carlclone 2018-06-02 13:05:57 +08:00
恕我直言你层次没他高
|
9
takato 2018-06-02 13:09:48 +08:00
1 的话,一般成熟的系统中 使用 二进制编码转 int 比较多一些。这个比较好扩展,因为如果哪天你要塞一个维度的类型进去,但是又不动表结构的时候可能会有优势。
对于另外两个问题我持中立态度。。 当然我能感觉得出来,你纠结可能是因为对方在说明他自己的方案的时候,没有讲解清楚方案的优势以及改进初衷。 我个人的看法是你俩各有一半责任。给方案如果能不仅局限于方案本身,同时把方案所能造成的影响也做一个归结整理,这样沟通起来才会容易一些吧。 |
10
hjdtl 2018-06-02 13:10:27 +08:00 4
总结:前端不算开发
|
11
doubleflower 2018-06-02 13:12:57 +08:00 via Android 2
你应该问问他遇到你这样的难不难受
|
12
E1n 2018-06-02 13:20:43 +08:00 via Android
哈哈😄
|
13
janus77 2018-06-02 13:25:04 +08:00
所以大型项目考虑最多的不是优雅 甚至不是性能,而是规范。对于超大量的项目来说,重写重构才是最大的成本阻碍,所以无论如何要先确定好规范
|
14
TabGre 2018-06-02 13:25:06 +08:00 via iPhone
前端是设计师吗?
|
15
Immortal 2018-06-02 13:29:11 +08:00
看来我应该也被同事讨厌了..1 2 3 的事情我遇到也会和 C 做的一模一样
|
16
enenaaa 2018-06-02 13:40:45 +08:00
楼主心里难受是因为双方没摆正自己的位置, 所谓一山不容二虎,除非一主一仆。
如果选不出老大,最好大家都不当老虎。要么以理服人,要么各扫门前雪。 |
17
zengmingyang96 2018-06-02 13:42:25 +08:00
我认识一些厉害的,都是依赖于直觉,相信比你厉害的,直觉比你准
|
18
WillieYang 2018-06-02 13:46:53 +08:00 via Android
@hjdtl 笑尿
|
19
lsls931011 2018-06-02 13:51:43 +08:00
恕我直言,1,2 条是对的
|
20
zgray 2018-06-02 13:57:00 +08:00 via iPhone 1
不说技术我觉得这里 C 表现的更多是以经验压人。而这种经验不见得就一定是好的。
问题 1 说的类型用 int 也不一定扩展就好,我们还用过 char(1)的,符合业务场景就是好的。对于以后扩展,很多时候不仅仅是加类型,也可能变更类型,比如原来有个出库类型是销售,可能随时间推移会出现海外销售和国内销售,这时候可能会希望原来的销售编号做分离,这时候无论哪种都没那么简单。 问题 2 自增的是可以考虑但是没有给出理由,楼主的 uuid 也没问题,uuid 在未来有数量迁移和库表合成有好处。而且 uuid 把时间区信息调到前面一样可以解决排序问题。如果数据大要排序,加个整型的排序字段比自增更有意义。主键唯一除了 uuid 还有 twitter 的雪花算法产生 id。数据库中并没有谁规定一定要自增列,比如 oracle 的自增是靠序列实现的,而主键列我们也不直接用序列,而是拼接上一个前缀。同时业务场景中往往不会直接按主键排序,所以自增完全看场景,没有一定的说法。 问题 3,删除没用代码有好处,但是如果是重载方法就不见得删除的好,更多可能要评估为什么当初要写出这种代码,比较有时候调用送 list 还得产生一个 list 对象,而这个 list 才一个实体,那这时候的 list 产生意义就很低了,多了内存占用确只是为了兼容。 总之我是认为事情要商量,要以理服人,不能老是说经验。 |
21
codermagefox 2018-06-02 13:57:09 +08:00
总结:前端不算开发.
我 JS 小红卫兵此刻只想对准楼主一顿输出 |
22
ty89 2018-06-02 13:58:23 +08:00 1
很明显的,C 比你经验丰富老道,他只是懒得跟你解释那么多而已
|
23
takato 2018-06-02 14:05:11 +08:00
另外很明显,如果楼主按照 3,2,1 的方式来叙述,下面的回复会大不一样。
|
24
missdeer 2018-06-02 14:20:22 +08:00
有点疑惑上面为什么一面倒的说 C 对,我觉得就这 3 个问题来讲,更多的是种风格 /喜好的问题,就跟大括号要不要换一行写是一类问题,没谁对谁错谁好谁坏的
|
25
scriptB0y 2018-06-02 14:25:19 +08:00
1 我觉得 varchar 可读性高一些啊
|
26
IvanLi127 2018-06-02 14:34:17 +08:00 via Android
如果 c 讲清楚为啥要这么干,估计就没这事了。没沟通清楚而已。
|
27
zr8657 2018-06-02 14:37:49 +08:00 via Android
12 同意 c,3 同意楼主
|
28
Lax 2018-06-02 14:48:29 +08:00
1. 他的理由很充分。最后没按他的操作。
2. 他的理由很一般。按他的操作了。 3. 他的理由很一般。按他的操作了。 感觉是楼主没做出关键的决定。提升自己的实力能有效防止这种“理念”问题。 |
29
arthasgxy 2018-06-02 14:51:50 +08:00 1
@zgray
我咋觉得 C 更像是懒得解释…… 1、正常来说 varchar 有极高(最高?)的兼容性,比如碰上一个傻逼产品非要在一个 int 字段里面,加入字符信息的。但这种毕竟是少数,多数情况下,我反而更希望不小心在一个 int 字段插入 string 时报错而不是“兼容” 但你要真问我“一定”能有啥问题?项目初期我也说不出,毕竟我要告诉你那些很傻逼的情况会出现,你可能反而觉得我很小白,怎么可能出现那种情况。我还不如让你自己经历。 PS:这里的“你”指楼主,“我”假定我是 C 2、以一个非常简单的东西为例,某个表并非我维护,但只有我插入内容。我需要找一段数据的时候,我能大概记得这段数据在什么时候插入的。比如半小时前。然后我查一下自增主键最大值,再估算一下插入量(很多时候甚至凭感觉就行了),然后就找到位置了。order by 查最大主键 + 估算位置,算上输入大约半分钟? 反过来,如果只有个萌萌哒的 UUID,是不是我只能用 ts 来估算? ts>=unix_timestamp('xxxx-xx-xx xx:xx:xx') and ts<unix_timestamp('xxxx-xx-xx xx:xx:xx') limit 100 效率真的低。。。 3、不做评价…… |
31
xiaochocking 2018-06-02 14:57:13 +08:00
总结:前端不算开发
我是切图的 |
32
msg7086 2018-06-02 15:03:30 +08:00
1)
枚举本来就是数字,用 int 没问题。varchar 通常不是最佳实践,除非有很特殊的需求,否则我觉得不合适。 2) 每个表有一个自增主键也算是最佳实践吧。和上一条一样,除非特殊需求,否则建议按照最佳实践加上。 3) 这个见仁见智吧,如果调用端都已经改用新接口了,老的可以删除。 主要目的是减少冗余代码量。 你想想,这套系统经过无数人敲打,两三年的时光过去以后,现在要改这个接口了。 问你,这个接口现在还有人用吗? 你:不知道。 问你,那要不要花宝贵的人力物力去改这个接口呢? 你:不知道。 还有更惨的—— 问你,这两个接口里有一小段代码不一样啊 ,两个版本里哪个才是对的? 你:不知道。 这就完蛋了。 (别问我为什么知道的……满满的都是泪…… |
33
taro0822 2018-06-02 15:08:02 +08:00
其实 LZ 的真正目的是来黑我大前端的(逃
|
34
a7a2 2018-06-02 15:08:44 +08:00 1
1、能使用 int 的别用 varchar
2、uuid 即可,别再加一个自增,自增不适合大数据及将来转换到 tiDb 之类的分片数据库 3、c 太强势,不尊重人,相互合作的人家也一样写了代码应该问一下对方需要 |
35
hjdtl 2018-06-02 15:10:01 +08:00
@WillieYang 其实全文是对前端高端黑!不显山不露水👍👍
|
36
micean 2018-06-02 15:19:26 +08:00
1,如果想要可读一点,可以设计成长度一致在 4 以内的缩写,用 CHAR 代替
2,自增键可以用来比较大小、排序 |
37
GuuJiang 2018-06-02 15:23:06 +08:00
1、你想象一下对 int 和对 varchar 进行相等或者大小比较时哪个效率更高
2、用 uuid 作主键是一种很糟糕的实践,因为主键都是聚集索引,数据行在存储引擎中的位置是按聚集索引顺序排列的,这也是“聚集”的含义,而使用 uuid 作为主键时会导致每次插入几乎都会伴随着数据的移动(这一点未确认,没有查到权威的资料证实),而使用与业务无关的自增主键则可以最大发挥聚集索引的作用 3、应该在项目最开始就考虑到给接口加版本标识以应对这种情况 |
38
whoisghost 2018-06-02 15:23:42 +08:00
同感觉 c 太强势,不喜欢这样的人,就算他是全对的也不喜欢。要说服人,就要在特定情景情况下,拿出 1,2,3 理由来,拿经验压人是表达无力的表现。
|
39
oovveeaarr 2018-06-02 16:21:55 +08:00
@GuuJiang #37 关于 3 这一点,mysql 的 innodb 和 myisam 应该 不成立,因为表大了经常会有表中删除了一条,再次插入的时候新的记录会占据那条已经删除的数据的位置,我估摸着是因为内部为了性能有网孔(空隙)。
|
40
zjsxwc 2018-06-02 16:25:05 +08:00
第一个我觉得用 int 更好,type 应该会被用于搜索,int 效率比 varchar 好,而且可读性上 int 也可以接受。
第二个我觉的差不多,但是自增 id 查询时效率高不少,而且可以根据自增特效做些别的操作。 第三个,我倒不会去删,但会把传单个参数的那个函数,内部实现改为调用 list,避免以后出现改了 list 业务代码,但没改单个参数的业务实现,这种低级错误。 |
42
GuuJiang 2018-06-02 16:46:13 +08:00
@oovveeaarr myisam 确实是你说的这种情况,因为 myisam 根本就没有聚集索引,采用的是“堆式”存储,就类似于系统的操作系统堆内存的分配一样,插入记录时从可用空间中分配,删除以后回收为可用空间,而 innodb 每个表有且仅有一个聚集索引,行数据是伴随着聚集索引一起存储的,所以自增主键是十分有必要的
|
43
wizardforcel 2018-06-02 16:47:07 +08:00
能删的代码尽量删,这样可以强迫大家都学着用版本控制工具
如果哪天要用了,可以从历史提交中找回来,显得你的工作量比较大 XD |
44
notreami 2018-06-02 17:01:53 +08:00
前两个都是扩展问题,不好评论。毕竟还有过度设计的问题
第三个,内部实现合并起来比较好,统一实现。但是接口也合并,请求耗时监控就不好区分了。TP50 与 TP90 可以天差地别。 |
45
xiaket 2018-06-02 17:05:40 +08:00
这都还谈不上理念问题, 都只是代码审美观不一样罢了
|
46
takato 2018-06-02 17:27:15 +08:00
第三个问题有一个比较现实的例子。。
一些金融交易所会同时提供插入一个订单和插入一批订单的接口,但是在两个不同的 URI 下的,且会同时提供。 接口的消耗不一样,同时存在有时候也是有意义的。 |
47
1762628386 2018-06-02 17:32:40 +08:00
都没回答到点子上 这明显是制度问题 楼主公司明显没有 代码 /开发规范 才会出现这种上级强压下级服从的情况
|
48
akira 2018-06-02 17:44:02 +08:00
2. 个人习惯是 所有的表,都应该有一个 业务无关联的自增字段。另外还有可能要 2 个字段 记录创建时间和最后更新时间.
|
49
blless 2018-06-02 17:51:55 +08:00 via Android
1 3 很多人讨论了,2 关于 uuid 主键的问题 游戏那种区服要合服你们就可以感受自增 id 的痛苦了,尤其还依赖自增 id 干了啥事 当然单个库就当我没说,自增主键还是很爽的
|
50
q397064399 2018-06-02 17:58:07 +08:00
@oovveeaarr #39 B+树的特性就决定了 顺序插入是最好的
|
51
q397064399 2018-06-02 18:03:02 +08:00
Innodb 是聚集索引,,所有行信息 都是存在 主键列,所有索引列 非覆盖索引方式的查询 需要查询完索引后,通过主键 id 找到完整的数据行,所以很多时候为了性能一般会采取覆盖索引查询的方式 ,主键列是 b+树实现,b+的特性决定 顺序插入是最理想的,另外分库分表 应该以其它列的 hash 来决定。 另外整个 innodb mvcc 多版本并发机制了解一下
http://hedengcheng.com/?p=771 这篇文章值得一读。 |
52
wangxiaoaer 2018-06-02 18:15:50 +08:00 via Android
@arthasgxy 你们的数据库表记录都不加时间戳的?
|
53
arthasgxy 2018-06-02 18:23:14 +08:00
@wangxiaoaer 不就我说的 ts 么
|
54
arthasgxy 2018-06-02 18:25:16 +08:00
@wangxiaoaer 我的意思是,比如我大概有印象,一个表, 每分钟入库 1000 条。
大约半小时前的数据 就是 max(id)-1000*30 对不? max(id) 一般个人习惯是 order by id desc 看一下, 剩下的脑算一下就有结果了。 而用时间戳, 你要转换时间才能大概锁定位置不是么 |
55
sagaxu 2018-06-02 18:31:47 +08:00
1,枚举类型用 int 还是 string? 当然是 int 了,然后再定义一张 reference 表,描述各个 int 的含义
2,自增还是 uuid? 业务决定,一般无脑自增,除非数据量过十亿或者有不同 db 并表的需求 3,支持 list 接口还要支持单个的吗?维护一个接口比维护两个接口成本低,调用 list 比调用单个的成本差不多 |
56
wangxiaoaer 2018-06-02 18:44:45 +08:00 via Android
@arthasgxy 我是觉得时间转换很直观,数据库内置的日期函数比较放便。
|
57
my3157 2018-06-02 19:42:30 +08:00 1
1. 枚举大多还是会用 int, 有时候为了可读性也会用 string, 但是对于比较复杂的, 比如库存, 支付等, 会仔细规划一下, 不会采用 1,2,3 这样连续的, 一般会先规划好每个段, 比如 1-100,101-200, 好处是有时候会需要用范围查询, 简单情况下, int 和 string 没区别, 个人喜好
2. 同意 @sagaxu #55 一般无脑自增, 集群情况下要特殊考虑, 现在很多 mysql 集群方案是多主, 自增需谨慎 3. 接口不要随便删, 尤其是有外部依赖的时候, |
58
helloworldgo 2018-06-02 22:06:58 +08:00
理念不同我能接受,不能接受脾气合不来的,现在就有些同事是话没说两句就不耐烦,跟欠钱了似的。
|
59
yuanfnadi 2018-06-02 22:33:55 +08:00 via iPhone
如果是 innodb,使用自增 id 更好,这个数据库都储存方式有关。楼上说得很清楚了。
|
60
wr410 2018-06-02 22:52:49 +08:00
第一个,做数字比较的时候就有区别了。但是如果只是做标识,那标识就别定成数字不就好了,这样你就可以理直气壮了;
第二个,uuid 做主键本身没问题,考虑到数据量很大的时候就有区别了,至少浪费空间吧; 第三个,这个时候就应该好好利用重载了,主方法写在原子参数上,然后 list 什么的包装方法就直接循环调主方法就可以了; |
61
konakona 2018-06-02 22:54:09 +08:00
就第一个问题,整形需求,你非要 varchar,你会逼死很多才水平比较好的程序员……这是规范问题,不是节省空间得问题啊~~~~~~
|
62
Inside 2018-06-03 11:25:53 +08:00
楼上一大堆说表示类型用 int 更佳的,我就想问你们,你们是基于什么原则?
我的原则是,如果类型之间仅仅是互斥,并没有排序、优先级的潜在需求,用 string ;反之用 int,因为数字是有顺序的,可以用来表示优先级,没这种需求的时候不要乱用 int。 |
63
wangxiaoaer 2018-06-03 11:58:27 +08:00
@Inside #62 枚举用 int 保存 value 是很正常的吧,比如男生 1,女生 2,日后需要男生改成男人,难不成你还到数据库里面把所有的男生改成男人?
另外如果枚举文字比较长比如 xxx 出版社这种,int 明显省空间吧。 |
64
lain0 2018-06-07 00:11:44 +08:00
我反对「用 UUID 作主键是一种很糟糕的实践」的觀點,UUID 会容易重复是一個常見的誤解。
UUID 的长度是 128-bit,其中随机的 bit 有 122 个。如果生成 ~2^61 个 UUID 以上才会有 50% 的概率存在碰撞 。2^61 量级大概是怎样的呢?换句话说如果每秒生成十亿个 UUID,连续生成 85 年才能达到这样的数量级。单单要把这些 UUID 都存到硬盘上,就要占用 45EB/45,000PB/45,000,000TB 的容量,大于任何现有的数据库的容量。根据数据报告显示,这个数量级比 2016 年全年互联网的移动网络传输量还要大。绝大多数情况下几乎完全没有理由担心 UUID 的碰撞。 UUID 的全称是 Universally unique identifier,其含义就是使 UUID 尽可能唯一。 UUID 的好处正是因为无序,即不担保任何生成的顺序,这当你的数据纪录的创建顺序无法得到保证时(或者根本不希望纪录本身自带顺序属性时)非常有用。譬如说并行运行多个应用实例同时插入数据时,自增的数字 ID 可能会碰撞,而 UUID 就可以保证唯一。 关于用主键排序,我个人认为主键排序反而是种不好的实践,因为有序性并不是主键的属性之一,只因为恰好多数情况下主键的顺序和创建顺序一至不代表这样就可以依赖这样的属性。更好的做法是给每条纪录添加 created_at 和 updated_at,显式标明创建和修改时间,并明确以这两者排序。 参考资料: - UUID 碰撞概率的计算: https://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions - 互联网传输数据量报告: https://thenextweb.com/contributors/2017/04/11/current-global-state-internet/#.tnw_8pHvZxpk |