订单号和 id 列可不可以是同一列?

简介: 在分布式场景中,单表已经不能满足我们的需求了,所以用自增 id 的方案也就不合适了。当比如我们进行分表设计时,主键列到底如何生成就成了一个问题,流行的方法是利用像 snowflake 这样的算法计算出一个趋势有序的值作为 id。(当然还有其他多种方法)这样就满足了扩展性和一定程度上解决了检索性能的问题。

id 列


首先说 id 列一般作为主键,没有什么业务含义,设计的目的是为了查询和索引方便,如果用单表的情况下一般会设置为自增,有序了以后,无论数据库还是业务检索起来效率都非常高。


在分布式场景中,单表已经不能满足我们的需求了,所以用自增 id 的方案也就不合适了。当比如我们进行分表设计时,主键列到底如何生成就成了一个问题,流行的方法是利用像 snowflake 这样的算法计算出一个趋势有序的值作为 id。(当然还有其他多种方法)这样就满足了扩展性和一定程度上解决了检索性能的问题。


订单号


订单号的生成一般有相应的规则,而这些规则是各自产品根据自己情况自行设计的结果。


举几个例子


京东的:

  • 京东 2013 年的订单号 :479000238
  • 京东 2014 年的订单号 :7783813454
  • 京东 2018 年的订单号 :81467423041
  • 京东 2020 年的订单号 :132971864529


淘宝的:

  • 淘宝 2012 年的订单号 :230447522918072
  • 淘宝 2016 年的订单号 :2131062693288072
  • 淘宝 2019 年的订单号 :329062467847108072
  • 淘宝 2021 年的订单号 :2075316735066108072


可以看到京东和淘宝的订单号都是在递增的,而且淘宝的看起来是有规律的,这个查了一下有说从 2017 年淘宝升级了订单,原先是用订单号后 4 位识别用户,2017 年以后改为用后 6 位了。


“那么淘宝订单编号后 6 位用户 id 后 6 位的目的是什么?翻遍了百度、知乎,没有找到答案。我是偶然间翻到一份淘宝技术演变 PPT,看到订单表分库的逻辑时才恍然大悟。一般的平台型电商,订单量大,为保证查询检索速度,都会采用分库的形式,将巨量的订单信息分库存储,一般情况下订单系统同时维护了一个订单号和 userid 的关联关系,先根据订单号查到 userid,再根据 userid 确定分表进而查询得到内容。而淘宝在订单号上下功夫,通过订单号后 6 位直接锁定库表,大大提升高并发下的系统查询性能。从这个策略我们也可以看到淘宝用户订单库是按照用户 id 后 6 位存储的,例如:XXXX452154 格式的用户订单都是储存在一个分库中。


我通过查询发现自己的淘宝 id 后 6 位是 107280,而我的订单号后 6 位是 108072,还是有规律的。


找到了一个淘宝 2012 年的 PPT,可能 12 年之前的设计又不一样。


37.jpg


订单号生成规则


不重复显然,这种具有唯一标识的号码是不能重复的,安全不能被人为的猜测或推测出来,易识别易识别就代表位数不要太长,位数控制好了就容易查询检索,占用空间小。

几种常见的规则


  • 年月日+自增长数字的订单号(比如:2012040110235662)
  • 字母+数字字符串式,字母有包含特别意义,C02356652
  • Snowflake 算法生成
  • 年月日+机构编码+后四位随机


订单号可不可以作主键 id 列


前提是你根据你自己设计或选择的订单号规则生成了一个可行的订单号,这种情况下,如果你的订单号包含字母等字符串那么是不合适作主键的。虽然唯一,但索引查询性能较差。不过可以做唯一索引。


如果订单号是纯数字呢?


也不建议,数字当然有它的优点,性能好(位数长了也不好),但是订单号毕竟是跟业务相关的,与业务相关的列作主键本身可能会有问题。


假如未来的一天我们要改变业务含义,也许想把数字改字母,加几位或少几位,那么就必须修改主键了,核心数据表的主键修改,可是牵一发而动全身的,会造成极大的维护开销。


虽然直观上感觉“多了一列”,但并不是无用的,对未来的扩展性会有很大帮助。综上,回答我们标题的问题:“订单号和 id 列可不可以是同一列?” 或者说订单号可不可以作主键,我认为可以,但不适合,所以建议不要用订单号做主键。用与业务无关的 id 列作主键比较合适。


主键列怎么设置?


如果是单表,当然是用自增 id, 如果考虑到分库分表,可以采用像 snowflake 这样的生成方案。




相关文章
|
6月前
|
存储 关系型数据库 索引
10. 在一个非主键字段上创建了索引, 想要根据该字段查询到数据, 需要查询几次 ?
在非主键字段上创建索引,查询数据通常需两次。对于MyISAM,先通过索引找到数据行指针,再获取数据;而InnoDB则先找主键ID,再从主键索引中查找数据。
42 0
|
6月前
|
SQL 关系型数据库 MySQL
Mysql数据库一个表字段中存了id,并以逗号分隔,id对应的详细信息在另一个表中
Mysql数据库一个表字段中存了id,并以逗号分隔,id对应的详细信息在另一个表中
42 0
|
SQL 存储 运维
order by 字段到底要不要加索引?[大坑]
order by 字段到底要不要加索引?[大坑]
199 0
order by 字段到底要不要加索引?[大坑]
|
SQL
一条集多表查询、字段与字段拼接、合并每张表共同字段、新增列并赋值的SQL
一条集多表查询、字段与字段拼接、合并每张表共同字段、新增列并赋值的SQL
66 0
|
SQL 关系型数据库 MySQL
MySQL变量使用与介绍之为查询结果增加序号列和自定义序号列
SQL三:用户表(包含字段有:用户ID[自增]、姓名、性别、民族、出生日期、身份证号),无论查询条件如何,要求查询的结果显示一个行号列(即:第一行显示1,第二行显示2,第三行显示3,依此类推)
254 0
|
前端开发 数据库
FineReport中使用一个搜索框查询数据库中多列值返回一列值:使用union函数
前端使用一个查询框(搜索框)查询数据库中多列值,这里使用数据库的union函数进行实现
233 0
DataTable 修改列名 删除列 调整列顺序
DataTable 修改列名 删除列 调整列顺序
213 0
|
SQL 算法 测试技术
Guid算法与标识列(自动增长字段)在表中的应用
Guid算法与标识列(自动增长字段)在表中的应用
180 0
Guid算法与标识列(自动增长字段)在表中的应用
|
关系型数据库 MySQL
mysql更新一个表中的姓名字段,随机取出姓,名部分截取该表中另外一个字段拼接...
mysql更新一个表中的姓名字段,随机取出姓,名部分截取该表中另外一个字段拼接...
251 0
mysql更新一个表中的姓名字段,随机取出姓,名部分截取该表中另外一个字段拼接...