船舶管理数据库结构讨论(应该非规范化?)

时间:2009-02-12 00:33:31

标签: database database-design normalization denormalization

我的软件几天前投入生产,现在我想对数据库结构进行一些争论。

该软件收集有关船舶的数据,目前每艘船的174个细节,每个细节可以是文本值,长文本值,数字(指定长度,有或没有指定的小数),日期,包含时间的日期,布尔字段,包含许多值的菜单,数据列表等。

我用下表解决了这个问题

Ship:
- ID - smallint, Autoincrement identity
- IMO - int, A number that does not change for the life of the ship

ShipDetailType: 
- ID - smallint, Autoincrement identity
- Description - nvarchar(200), The description of the value the field contains
- Position - smallint, The position of the field in the data input form
- ShipDetailGroup_ID - smallint, A key to the group the field belongs to in the data input form
- Type - varchar(4), The type of the field as mentioned above

ShipDetailGroup
- ID - smallint, Autoincrement identity
(snip...)

ShipMenuPresetValue
- ID - smallint, Autoincrement identity
- ShipDetailType_ID - smallint, A key to the detail the values belongs to
- Value - nvarchar(100), The values preset in the menu type detail

ShipTextDetail
- ID - smallint, Autoincrement identity
- Ship_ID - smallint, A Key to the ship the detail belongs to
- ShipDetailType_ID - smallint, a Key to the detail type of the value
- Text - nvarchar(500), the field containing the detail's value
- ModifiedDate - smalldatetime
- User_ID - smallint, A key to the user table

ShipTextDetailHistory
(snip...) 
This table is the same as the ShipTextDetail and contains every change to the details.

Other tables for the list detail type, each with the specified fields required for the list, ...

我刚读过这篇文章:http://thedailywtf.com/Articles/The_Inner-Platform_Effect.aspxhttp://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:10678084117056

文章说这不是解决问题的正确方法。

我的客户在更改详细信息说明并添加更多详细信息时,有详细信息和组的管理gui。

通过从DetailGroups和DetailTypes读取结构来动态构建数据输入表单,每个详细信息类型都会生成指定的输入控件。

评论表明,解决此问题的另一种方法是动态创建和删除表中的列。

您怎么看?

图表截图:http://img24.imageshack.us/my.php?image=66604496uk3.png

4 个答案:

答案 0 :(得分:4)

如果符合以下条件,我会refactor您的代码:

  • 您的客户抱怨
  • 你找到了一些不起作用的东西
  • 你找到了代码无法处理的方法 改变你知道会发生什么 在将来。

你记得写单元测试可以让你重构,对吗?

*就你所拥有的结构而言,我之前已经看过类似的结构。它有点麻烦,但它在许多地方都是标准配置。要记住的一件事是,尽管可以动态添加和删除数据库中的列,但数据库的内部存储机制并不一定要求您连续添加和删除这些列。但我不认为这与上述要点相比非常重要,可归结为: *是否有效?

答案 1 :(得分:4)

我以前见过这种方法,一旦数据量增长,就会出现大量的性能问题。当您需要返回多个项目并在where子句中使用多个条件时,您遇到的问题就会出现。您在Ship和ShipTextDetail之间来回连接以获取所有选择列 - 也许您必须这样做10/20次?然后你可以为你的标准做同样的事情2-3次。现在你有一个有这么多连接的查询,它运行得非常慢。接下来,您“预先烹饪”一些数据以提高性能,即将常用数据拖出到固定的表结构中 - 啊,您已经返回到半规范化模型。

我的建议是这样的 - 您知道174个字段的信息,这些是您的核心属性。您的客户可能会添加到该列表,并可能会更改字段的描述,但它仍然是一个非常好的起点。根据这些创建一个合适的DataModel,然后像您已经完成的那样构建可扩展性机制,但仅限于新字段。元数据 - 字段的描述,可以驻留在另一个表中,或者可能存在于资源文件中(对国际化有用吗?),并为现有字段提供一些灵活性。

我同意Joe的意见,如果你的数据库很小,你可能没有问题,即< 1000艘船并且你的选择很简单。虽然从中选择174个属性似乎不太可能。我认为你应该先改变一些“明显的”字段,即我假设你有Ship.Name,Ship.Owner,Ship.Weight,Ship.Registration ...

祝你好运。

答案 2 :(得分:0)

我做过类似的事情,但这个具体的实现存在一些问题:

  1. 您将数字,布尔值,日期等存储为字符串。这可能不太理想。另一种方法是为不同的数据类型实现单独的类(从基类继承),然后将它们存储在为其数据类型制作的表中。
  2. 您跟踪的属性是否经常更改?它们是每艘油轮不同的一套吗?如果没有,最好是制作对象而不是属性包来存储所有数据。然后可以将这些对象持久保存到数据库中。

答案 3 :(得分:0)

从绩效的角度来看,任何一种方法都可以。可能有多少艘船?所有数据都适合任何服务器上的RAM。