我们该如何设计数据库(四)
其实我一直在准备另一篇博文的基础资料,但是和朋友聊天,他问我最近在做什么,我说在做系统Log模块,并和他交流了一下,于是这篇博客就应运而生
我的博客目录:Index & Writing Plan
所有数据都可以用如下形式表述:ID,表名,列名,Value
比如说现在有这么一条数据要插入User表:
ID(Guid,这里为了方便理解用Int) | Username | Password | |
1 | CrazyJinn | 123456 | CrazyJinn@W.C |
这一条记录可以转换为:
ID | 表名 | 列名 | Value |
1 | User | Username | CrazyJinn |
1 | User | Password | 123456 |
1 | User | CrazyJinn@W.C |
你可以在各种对灵活性要求高的地方看到这种设计,比如说在《我们该如何设计数据库(三)》的留言中,就有园友提到了类似的设计
当然,这种方式效率不是很高;不过可以把聚集索引加到表名上,然后非聚集索引加在列名上,再水平分割一下,如果你心情好,再做个读写分离,相信就非高并发、千万数据量级的应用来说,理论上还是可以接受的
好了,现在进入正文
现在要做一个通用的Log模块
既然是通用的,那就意味着灵活性要非常强,因为你不知道Log中要记录的数据结构是如何的
而且给我的需求有一个非常变态的地方:要有回退功能。不过这个我们先不去管他
根据之前的讨论,我们可以很容易设计出一张Log表
ID | 表名 | 列名 | Type(Create\Edit\Delete) | Value | 最后修改时间 |
如果处理的全是无关系的问题,这样做就足够了。但是要知道,RDBMS,最重要的就是关系的处理
比如说要Log这样两张表:
上文所设计出的Log表面对这样的一对多关系是无法储存的,不要往了,我们还有多对多关系
当然可以拓展Log表来实现储存一对多/多对多关系,虽然我不确定能不能做到,因为我没有就这方面去深入的思考。如果您想到了好的设计,欢迎留言和我探讨
让我们来重新思考一下Log模块的本质:
1、大量数据
2、只是大量数据(和别的模块没有关联,纯粹的数据)
这种场景让我不由自主的想到了Nosql。在这里,使用MongoDB来实现。关于MongoDB入门,可以参考下面两篇文章:
Fish Li:《MongoDB实战开发 【零基础学习,附完整Asp.net示例】》
MongoDB使用Bson来储存数据,你可以简单的把Bson理解为Json。众所周知,Json是一个非常易于扩充的,松散的的数据格式;基于Json易于扩充的特性,我们可以这样来设计Log表
LogID | ID | 表名 | Content(所储存的内容,包含了最后修改时间,修改类型,以及新的修改ID) |
如果我对User表修改了6次,那么我们Log的数据如下图:
我们主要把注意力集中在上图用红框标注的3条数据上
第一条数据,ContactList是一个Array类型,长度为0,这表示没有对应的Contact
第二条数据,ContactList长度变为1,这表示这次修改为User添加了一个Contact的关联,我们将第二条数据完全展开来看:
可以看到,包含了一个完整的Contact进来
第三条数据ContactList为Null,这表示我在某个别的地方修改了User信息。这次修改没有涉及Contact,所以保存为Null。当我们取数据的时候,如果发现某个List为Null,就要递归的向上去查找不为Null的数据。例如我这里,就要去找到第二条数据的ContactList
为了方便大家理解,我把Json贴在下面。对照前面的图片可以很好的阅读
{ "Content" : [{ "_id" : new BinData(3, "mtonv7sMCkewsMIjWZ9/qg=="), "Username" : "1", "Password" : "1", "Number" : 1, "LastModified" : new Date("27/11/2012 10:28:18"), "ContactList" : [{ "_id" : new BinData(3, "1QwcXGKedUCO27QprZB26Q=="), "UserID" : new BinData(3, "YyQDfuoj6EuuDNl91leigA=="), "Phone" : "Phone1", "Email" : "Email1" }, { "_id" : new BinData(3, "EeWfiFCknkex4H2jEraR/w=="), "UserID" : new BinData(3, "YyQDfuoj6EuuDNl91leigA=="), "Phone" : "Phone2", "Email" : "Email2" }] }, { "_id" : new BinData(3, "Afk3spV0q0uKM+yNs/SHbw=="), "Username" : "1 to 2", "Password" : "1 to 2", "Number" : 2, "LastModified" : new Date("27/11/2012 10:35:03"), "ContactList" : [] }, { "_id" : new BinData(3, "H/5o2lizmUWkaxAZUgNHzg=="), "Username" : "2 to 3", "Password" : "2 to 3", "Number" : 3, "LastModified" : new Date("27/11/2012 10:40:28"), "ContactList" : [{ "_id" : new BinData(3, "7HDyGU2+A02HbQtUFbOo8A=="), "UserID" : new BinData(3, "H/5o2lizmUWkaxAZUgNHzg=="), "Phone" : "PhoneNew", "Email" : "EmailNew" }] }, { "_id" : new BinData(3, "zf2SiYW81kufGO7ZgY5r3A=="), "Username" : "3 to 4", "Password" : "3 to 4", "Number" : 4, "LastModified" : new Date("27/11/2012 10:41:34"), "ContactList" : null }, { "_id" : new BinData(3, "N68jDslbU0uvdHJTSq0vIg=="), "Username" : "5", "Password" : "6", "Number" : 7, "LastModified" : new Date("27/11/2012 17:14:12"), "ContactList" : null }, { "_id" : new BinData(3, "Fw6OqMNcc0K+rySfgz3dTg=="), "Username" : "9", "Password" : "9", "Number" : 9, "LastModified" : new Date("27/11/2012 17:16:15"), "ContactList" : [{ "_id" : new BinData(3, "zfsQRK5A0kGFFcnc5TZ9GA=="), "UserID" : new BinData(3, "YyQDfuoj6EuuDNl91leigA=="), "Phone" : "PhoneNew", "Email" : "EmailNew" }] }], "ModelID" : new BinData(3, "YyQDfuoj6EuuDNl91leigA=="), "ModelName" : "User", "_id" : ObjectId("50b4254257751f09a02decba") }
这样,一个Log功能的雏形就出来了
就此搁笔
PS:我写了个小的Demo,但是很乱,就不放上来了。有兴趣的朋友可以留邮箱,我会发过去的
/*=============================================================*/
作者:CrazyJinn
本文版权归作者和博客园共有,欢迎转载.但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
如果看完这篇文章让您有所收获,请点击右下角"推荐".
如果这篇文章让您觉得不知所云,或者通篇谬误,请点击右下角"反对".并且欢迎您留言给我提出宝贵的意见.
如果您想获知我最新的动态,可以在绿色通道中点击"关注我".
/*=============================================================*/