Heim > Fragen und Antworten > Hauptteil
现在正在做 REST API 的设计,在设计过程中遇到了一些困惑,问题是这样的:
比如我有一个订单表
order_id | products | status |
---|---|---|
1 | 笔记本电脑 | canceled |
2 | 华为手机 | finished |
3 | 小米手环 | delivering |
获取所有订单的接口设计如下,其中有一个可选参数是 status
可选值为 canceled
、finished
、delivering
。
GET /order?status=canceled //已取消的订单
GET /order?status=finished//已结束的订单
GET /order?status=delivering //配送中的订单
这样设计API,可读性还是很好的。但对这里的 status 字段有一些疑问,该字段在数据库中,是直接存储为字符串?还是存储为数字?
由于需要保证API可读性好,所以如果用 数字来存储 status ,那么就需要管理字符串与数字之间的对应关系。
比如说:canceled => 0
、finished => 1
, delivering => 2
但是这样子,就需要在程序上,对status做一些转换,会无形增加一些程序的复杂性。
我的问题是:能不能直接把 status
字段直接存储为字符型?,就像上面的设计一样。如果数据量大会不会造成性能问题?或者其他一些问题? 谢谢!
迷茫2017-04-17 13:18:30
一般是这样的 status一般是按顺序来排的数字
比如
0 - 订单生成
1 - 出库
2 - 已发货
3 - 派送中
4 - 已签收
5 - 已评价
6 - 已经取消
这样 你可以 通过status<4 查看没完成的订单
上面只是举例 你还应该有别的状态 退货 付款 退款啥的
这样是比较好的
迷茫2017-04-17 13:18:30
设计过些数据库, 类似于这种状态, 最早使用的是使用 int 来存储的, 因为相对于 varchar int 的效能是高的, 不过随之而来的问题是, 因此业务的问题, 会经常有查询, 但是在写 sql 的时候经常会忘记相应数字所对应的状态, 每次又要去找, 很烦, 加之又从互联网的某个角落得 知, 在 postgreSQL 中其实 int 和 varchar 的效能问题其实是没差别的(未经验证, 至少是我未验证过), 后一想就算是存储 varchar 状态最长把字符控制在十个字符内, 不会有很大的问题, 而且类似于状态这样的经常查询字段也会建立一个索引, 基本上已经可以了.
之前也听一个前辈说过, 他那有个库, 数据很多, 状态是 int 的查询速度是大于 varchar 的.
目前了, 状态字段又换成 int 型了, varchar 的便于识别的所带来的坏处就是在写 sql 语句的时候状态的条件需要多加 ' (where stat='open') , 对的 我就是这么懒.. 人都会偷懒, 而且也许会带来性能上的提升 何乐而不为了, 关于之前说的记不住状态, 有所得就有所失.
而且类似于这样的状态 如果存储的 int 型, 转换的话, 在 java 中可以定义隔枚举类作为对应的状态值, 这样程序判断会相对简单些.
关于说的数据大的问题, 如果你的表数据不会达到几百上千万的量, int varchar 的差别或许并不是很大, 当数据达到或者超出这个量的时候, 或许数据库都不一定能做到高效的操作了, 会考虑更多高效的方式, 像 nosql solr 等.
结论的话:
为了便于自己认识使用 varchar
为了高效(或者说专业设计)使用 int
如果确定用数字存储的话可以考虑用 tinyint 这个相对来说效能会高于 int 这个数值范围是小于 int 的, 不过是 postgresql 的话就不行了这数据库不支持 tinyint 类型
黄舟2017-04-17 13:18:30
int虽然不是那么容易看明白,但效率高很多,而且也有助于楼上说的做比较。可读性,可以使用类似枚举的手段来解决。前端传递来字符串参数可以试用哈希表转换成int的数值再做数据库查询。
数值和状态之间的对应关系一定需要用文档规范出来,写代码的时候查文档就行,方便不同开发人员之间协同开发。这方面没有规范的文档,即便你用字符型也不见得所有人都能看懂。
提一点,考虑将来状态可能会增加,建议不要取连续值(即“1 2 3 4 5”),类似“10 20 30 40 50”这样能够允许你以后增加状态的时候可以插入。
PHPz2017-04-17 13:18:30
其实这个用orm处理就好了
查询一般是这样的
Order.where(status: Order.statuses[:shipped])
黄舟2017-04-17 13:18:30
MySQL 支持enum类型,实际存储得是tinyint。可读性和效率兼具。
针对你的情况我举个例子:
首先看mysql这边的设置
CREATE TABLE t_order (
order_id int,
products varchar(64),
status ENUM('canceled', 'finished', 'delivering')
);
insert into t_order(order_id, products, status)
values (1, "笔记本电脑", "canceled"), (2, "华为手机", "finished"), (3, "小米手环", "delivering");
mysql> select * from t_order;
+----------+-----------------+------------+
| order_id | products | status |
+----------+-----------------+------------+
| 1 | 笔记本电脑 | canceled |
| 2 | 华为手机 | finished |
| 3 | 小米手环 | delivering |
+----------+-----------------+------------+
3 rows in set (0.00 sec)
程序端只要按字符串访问就可以。ORM对枚举也有很好的支持,以java+jpa为例子。
public enum OrderStatus { canceled, finished, delivering };
@Enumerated(EnumType.STRING)
private OrderStatus status;
巴扎黑2017-04-17 13:18:30
我认为定义一个枚举是比较好的,数据库直接存字符串类型
public enum Status {
CANCELED, FINISHED, DELIVERING
}
这样做,你的restful API 可以设计成这样:
GET /order/{status}