现在正在做 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”這樣能夠允許你以後增加狀態的時候可以插入。
黄舟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}