八卦一下自家管理系统数据库设计方面的几个问题(1)
时间:2011-01-01 来源:陈伟强
产品本身是一个c/s结构的管理产品,从开发角度来看,大粒度应用程序事务的色彩比较浓厚。我认为是介于事务系统和分析系统之间,偏事务处理一些。所以我们的优化方法和大部分网站,或者说很多同类产品优化的方向就不太一样。我们做不到那么细。例如,我们比较少要求服务器一秒钟内至少能处理多少最常用的请求,等等。我们面对的至多是1K级别的并发数量,数据量少至几条,多的可以达到10K条记录每次交互。所以,客户每点击一次按钮,系统能在几秒内做出反应这样的指标更加有意义。客户端按照呈现形式主要分几类模块:字典,单据,查询,报表,权限。按照组织形式有组织机构划分,业务类型划分。
我们采用的数据库管理模型是公司自己开发的,该模型原本是用来做微型的基于对象的内存数据库的。存储方式为XML,包括Schema和Data。大致表现形式如下:
<DB>
<Table>
<Name>MasterDJ</Name>
<Fields>
<ID>
<FieldKind>PrimaryKey</FieldKind>
<DataType>Int</DataType>
</ID>
<BZJGID>
<FieldKind>NormalData</FieldKind>
<DataType>string</DataType>
</BZJGID>
</Table>
<Table>
<Name>CLDJ</Name>
<Fields>
<ID>
<FieldKind>PrimaryKey</FieldKind>
<DataType>Int</DataType>
</ID>
<MasterDJID>
<FieldKind>ForeignKey</FieldKind>
<DataType>Int</DataType>
</MasterDJID>
<DJBH>
<FieldKind>NormalData</FieldKind>
<DataType>string</DataType>
</DJBH>
<SL>
<FieldKind>Calculate</FieldKind>
<CalcExpr>CLMX.SL[BillID=?ID].Sum<CalcExpr>
</SL>
</Fields>
<Records>
<Record>1, 1, '入库-01', 20</Record>
</Records>
</Table>
<Table>
<Name>CLMX</Name>
<Fields>
<ID>
<FieldKind>PrimaryKey</FieldKind>
<DataType>Int</DataType>
</ID>
<BillID>
<FieldKind>ForeignKey</FieldKind>
<DataType>Int</DataType>
</BillID>
<SL>
<FieldKind>NormalData</FieldKind>
<DataType>string</DataType>
</SL>
</Fields>
<Records>
<Record>1, 1, 20</Record>
</Records>
</Table>
</DB>
设计上没有什么特别。但是该模型最初的设计是为了呈现一个“完整”的业务模型,包括其内部业务逻辑。例如,当我改了CLMX表数量字段的时候,CLDJ表的数量字段可以自动更新,不需要代码或是手动干预。基于此,模型大量使用了“关系“这个东西。包括主外键关系,计算关系,约束规则全部都是自动处理的。因此这个业务模型里的数据可以少,但是不能不完整。例如有CLMX表一条记录,那么他的两条主表记录也要存在。我们的程序也受到了这一传统的影响。我要说的主要是以下两个方面:
1.主细关系层次比较深,因为无论多深的层次,模型都可以自动进行计算,约束等的处理。
举个例子,我要取一张单据的供应商可能要这么走:~MXID.~BillID.~HTID.~GYSID.Name
2.受1的影响,字典很多。在设计阶段,很多开发人员都倾向于将相同的东西提取成字典表。
我关心这两个方面的的原因主要是:1.表中冗余字段比较少,要取一条完整的数据,基本离不开表连接。做过数据库开发的兄弟都知道,连接操作绝对不是吃素的。数据量不必大,连接的左右两边各有100K的数据,即便连接列都建有索引,那客户端的响应时间就不好处理了。2.客户端每次向服务器端取的数据必须符合模型完整性,因此在数据的即时呈现方面不会太及时。再考虑着一条,客户端响应时间肯定会受一定影响。
我不知道我把问题交代清楚了没有,简单来讲就是数据库方面业务有些复杂,和“数据库就只存储数据“这样一个指导原则有些不太同路。当然了,现代的RDBMS功能是越来越强大,但是我觉得,无论什么时候,好的数据库的设计仍然是无可替代的。
好吧,考虑一个最实际的问题。查询效率差。对于大部分的全机构数据查询,一个返回结果数据量在1K左右的查询,很少能在3S之内完成。很多人都讲,数据库设计的时候不能完全按照范式来。即便是一个近似的第三范式,在一个大吞吐量的数据库里有时候也会让服务器吃不消的。数据库软件最擅长处理的是“基于集合的数据“。我个人认为,数据库软件就应该多处理IO密集操作,对于CPU密集操作,就应该分散到AppServer或者干脆客户端来处理。
领导也意识到了我们的SQL使用了过多的连接这个问题,前一阶段我们曾经一次性把所有的DJ表都冗余了一些主表里才有的字段,用来解决一部分问题。但是由于系统太庞大了,如果要做一些降低范式方面操作代价实在时太大。所以我们很多时候都在研究,怎么样通过一个合适的索引,怎么样把个别的表特殊处理一把,来解决个别查询的问题。
唉,写了一坨,似乎都是在揪表连接方面的问题。明天再八一八数据过滤的问题吧,也是很讨厌的。