2

数据库结构设计

 3 years ago
source link: https://www.zenlife.tk/database-design.md
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

数据库结构设计

2014-10-28

最近在项目中使用到aerospike和mongodb,不同的数据模型,一个是key-value的,一个是document的。做了些数据结构的设计,记录一些有意思的地方。

有一个需求是用户在一段时间内的访问次数,比如最近一个小时内访问了多少次,或者一天内多少次,一星期内多少次。利用记录的过期时间做这个很巧妙。用户首次访问后,生成三条记录,过期时间分别是小时,天,星期。key是用户uid,value是访问次数。后续访问中,原子增加value值,但是不要更新过期。等记录自然过期后就清零了开始下一轮统计。

分布式环境下的批量查询,由于批查的key是被分布到不同实例上面的,会跨机。有个性能要求很严格的场景,用key-hash结构避免跨机。比如(field1+field2,value)的key-value结构,批查询时field1+field2作为key会分布到不同机器上。而使用key-hash结构,field1作为key,value是一个hash。filed2作为hash结构的key,value为hash结构的value,field1固定,这种结构对field2进行批查时不会跨机,性能可能会好一些。

mongodb的结构好灵活,比如说一对多关系,可以这么存:

{ bagid : xxx, items : [item1id, item2id, item3_id], } { itemid : item1_id, }

也可以这么存:

{ bagid : xxx, } { itemid : item1_id, bagid : xxx }

哪种更合适呢?假设要获取某个背包中的物品列表,用第一种方式存是需要两次查表的:

items = db.bag.find({"bagid":xxx}, {"items": 1}) db.item.find({"itemid": {$in: items}})

而第二种方式只需要一次查表:

db.item.find({"bagid":xxx})

而且维护起来也是第二种方式更方便,比如在某背包中加入一个item,第一次方式除了需要改item表加入一项,还需要同时在bag表中对应项加入一条,而第二种方式只需要改item表。

但是也需要注意到,第二种方式如果没对bagid项建索引,查询其实是需要扫描的,而第一种方式则可以利用到主键索引。

多对多关系不要用引用或嵌入方式搞,虽然使用时查表可能方便一点点,但关系维护起来会非常滴蛋疼。还是老老实实地把关系拆到单独的表中维护。

web后端开发这边,一些项目就是围绕数据库的CURD操作,没什么技术含量,尤其是没有性能约束的时候想怎么整就怎么整。相对重要一点的就是数据库结构的设计要做好。核心部分是维护好规则。这里所谓的规则就是关系约束。

我觉得应该分为三层吧,最下层就是数据库表的设计要合理,有些冗余查起来会方便很多,但维护起来却很不爽,取折中的。在这个基础上封装提供各个表的CURD操作。

中间一层是最重要的,也是最麻烦的,就是维护操作的规则,不要破坏关系。比如读取一个表项,用户是否有操作权限。因为有些约束并不是数据库能直接维护的,可能有些级联的操作。比如添加一个用户的操作,不单单是在用户表中添加一项,可能还要修改对应的权限表,用户所属的群组之类的。

最上层就是提供给前端的接口了,需要什么样就做成什么样。中间层已经把操作的约束维护过,这一层就是给前端无脑调用了,前端不需要考虑约束什么的。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK