在上篇文章数据库设计中一个矛盾:数据库外键,用还是不用?你怎么看.? 中关于数据库设计外键使用与否的争论一直持续不休. 我从其中评论中也获得一定的启发. 早上雪太大 上班路上耽误不少时间,利用这段时间把这个设想做了出来. 当然有可能极为不成熟, 权当对一次猜想的验证.欢迎各位拍砖.
上篇的反方观点主要专注提取数据性能上问题比较突出:" 在海量的数据库中想都不要去想外键,试想,一个程序每天要insert数百万条记录,当存在外键约束的时候,每次要去扫描此记录是否合格,一般还不止一个字段有外键,这样扫描的数量是成级数的增长!"
针对目前的这个派单系统数据当量较大的特点. 暂且把这个主外建涉及其他影响因素都排外. 本篇主要专注讨论于在主外键关系下提取数据的性能问题. 早上看到上篇的评论后做了一个小小的猜想.设计如下:
设计中设计到四个表:
Order【派单表】-主表, 其中设计三个外键分别为:表ConfirmState对应ConfirmId外键, 表OrderState对应orderstateid外键, 表SystemUser对应uid外键
说明一下这四张表在系统中的数据特点:
Order【派单表】为系统核心实体,且是系统设计中用药频繁操作的表,每天数据更新次数较多, 但每次更新的数据量不定,总体数据当量偏大.
ConfirmState【状态确认表】为确认状态实体, 只有两个字段:主键和状态 状态涉及到数据:【 已经完工/未完工】 数据量基本更新的幅度和频率 较小. 属于系统级别的配置.
OrderState【订单处理状态表】为订单处理状态标注实体, 只有两个字段:同上, 状态中设计到五个字段:【申请/审核/处理中/已解决/未解决】特点同上
SystemUser【系统用户】系统用户为公司一个部门的员工, 数据量偏小,且设计到系统用户趋于一种稳定趋势发展.
其实如果细心应该能够发现对派单处理其实较为稳定流程来保证的,所以这点上用工作流WF来处理.
关系图如下:
首先分析一下:对于系统的核心实体Order派单表, 业务中每天数据频繁的增加,同时按精确日期及具体分类联合查询提取特定数据.等对数据的操作.在上文评论很多人都强调了对外键引用的表数据不宜较多,会出现一个性能与用户体验反应上一个"时间真空区". 这是一大弊病. 所以对于海量的数据外键引用,单单的从性能上讲我在原则上是同义上文反方的观点.
目前情况是三个外键数据量偏小,且数据变动可能性较小 总体数据是在系统级别的配置趋于稳定趋势.如果这样加以变动.
(1)引用时外键表一个稳定字段而非主键ID,在设计中我们解除这种实际数据库中表与表之间的主外键依赖, 转化到业务逻辑程序中加以控制.
(2)同时又能保证提取数据时能够提取到准确的数据,(当然有可能性能提高幅度不是太明显) 解除后图:
上午做了一个数据提取实例我用CodeTimer测试一下取一千条数据,对比一下和昨天晚上相差不大:
Time Elapsed: 19,304ms Time Elapsed: 14,221ms
CPU Cycles: 22,475,810,124
Gen 0: 2051
Gen 1: 0
Gen 2: 0
CPU Cycles: 16,554,201,551
Gen 0: 2247
Gen 1: 0
Gen 2: 0
性能上还是没法保证.