mysql字段数量不确定_不定字段数⽬的数据库表设计和数据结
构学步园
两难的境界:不定字段数⽬的数据库表设计和数据结构
昨天项⽬组会议上讨论的关于不定字段数⽬的数据库表问题并没有结果,今天继续分析之后发现问题可能还更⼤。当时讨论的结果是可能采⽤四种技术:
动态增加数据库表字段
预留⾜够的空⽩字段,运⾏时作动态影射
⽤xml格式保存在单字段⾥
改列为⾏,⽤另外⼀个表存放定制字段
现在我们来分析⼀下四种技术的优劣,不过⾸先可以排除的是第⼀点动态增加字段的⽅法,因为在实际操作时候⼏乎是不可能的(sqlserver 太慢,oracle索性不⽀持),基本可以不讨论就排除。剩下后三点。
先来讨论预留空⽩字段的⽅法,基本原理就是在数据库表设计的时候加⼊⼀些多余的字段,看下⾯的代码:
CREATETABLESample(
namevarchar(12),
field0varchar(1),
field1varchar(1),
fieldNvarchar(1)
}
然后看实际运⾏时候的需要,动态分配字段给系统使⽤,也许需要⼀个这样的结构来描述分配情况:
publicclassAvailable{publicintCurrentUnusedFieldNumber;publicHashtable FieldToRealName;
}
也许某⼀时刻的数据状况是这样的: CurrentUnusedFieldNumber=3, 哈西表FieldToRealName包含内容是("field0"="SomeId",
"field1"="AnyName", "field2=IsOk")
现在的问题是如果要配合Hibernate,如何来处理?以上段的数据使⽤状况为例⼦,如果我们的类定义是这样:
publicclassEntity01{publicstringName;publicstringSomeId;publicstringAnyName;publicboolIsOk;
}
也许只需要修改⼀下l,把 SomeId 和 field0 做成对应就ok了。但是在运⾏时我们怎么知道会有这样的类定义?除⾮我们做动态代码⽣成,⾃动编译也许可以,但是问题也许就到其他⽅⾯去了;如果我们不⽤动态定义,那么类就只能是这样:
publicclassEntity01{publicstringName;publicHashtable ExtraFieldAndValues;
}
使⽤的时候,⽤ entity01.ExtraFieldAndValues.setValue("AnyName", "boss") 的⽅式来引⽤,也许这样是修改最少的了,但是问题是Hibernate不⽀持这样的⽅法。
再来讨论单字段存储的⽅法,我们使⽤这样的数据库表定义
CREATETABLESample
(
Namevarchar(12),
Xml CLOB(102400)//仅作说明⽽已
)
然后对应这样的类定义
publicclassEntity01{publicstringName;publicstringXml;publicHashtable ExtraNameAndValueFromXml;
}
我们的代码就可以这样使⽤:string id = Value("SomeId") 了。这样解决看起来很不错,不仅不需要Available表,⽽且看起来Hibernate对它的⽀持也很完美,但是致命的问题在于:如果保持⾼效的查询?除⾮数据库系统本⾝对此有⽀持,否则就只能⽤低效的substring或者like做查询,这在⼤批量数据中根本就不可⾏。
是不是折衷⼀下,把两种⽅法的优点和起来?问题有来了:怎么保持两者之间数据的同步?难道要我们⽤存储过程去解析xml内容?
所以,⼀个两难的问题,需要我们认真去解决。我们通过认真的需求分析,也许可以减少可变字段的数量,但是只要有⼀个可变字段或者可变的可能性存在,我们始终要去解决这个两难的问题。
期待继续讨论。
(新增部分)
还有⼀种⽅法就是改列为⾏,⽤另外⼀个表存放扩展字段,定义可以如下:
CREATETABLESampleFields
(
idSampleInteger,
fieldNamevarchar(30),
fieldValuevarchar(100)
)
其中idSample关联到Sample表的id字段(我没有写出来)。这样的话,Hibernate很容易⽀持,也可以⽀持Sql的查询,⽽且可以⽀持把内容放到Hashtable中去,看起来是⽬前最好的⽅式了。但是在⼤容量数据的时候,SampleFields表的数据会是主表数据量的N倍(看定制的字段数⽬多少⽽定),同样存在有很严重的性能问题。
哪位⾼⼈还能再给⼀个⽅案?
---------2005-7-22新增-----------
很多朋友给出了很好的建议,其中蛙蛙池塘 给出了⼀个表结构,因为看起来不甚⽅便,我把类图画出来如下:
图所表⽰的内容简单来说是这样:
1。⼀个很宽的表ProductAttributeValues,包含⽤到的⼏乎所有可能的类型的值,但是每次只能⽤⼀个类型的值
2。将可变的列转为⾏,存放到上表中
3。为了存放类型定义和⼀些下拉列表的内容,设计了ProductAttributeTemplates和关联的其他表
4。ProductListItems中存放Product中所有项的说明和顺序。
这种思路其实就是把产品的“知识级”(设计模式⽤语)和“操作级”都表现出来了,如果要划分,则图的左上⾓三个表属于“操作级”,其余的属于“知识级”。wljcan ⽹友建议我去看《设计模式》的“观察模式”,我发现上图其实就是⼀种和“观察模式”相似的设计。《设计模式》看了很久都没能看下去,不过这⼏天正在看“观察模式”,等有⼼得了,再来看看能不能对上图的结构修改⼀下。
怡红公⼦ 提醒说oracle和sql server对xml字段其实已经不错了,所以了⼀下,但是真的是既产品中恐怕还是不敢⽤,不知道性能如何。虽然采⽤xml⽅式是我最推崇的⽅法。⽽且⼀旦采⽤xml⽅式存储,恐怕就会有changyu⽹友提醒的数据类型问题,要存⼀个图⽚的话恐怕就歇菜了(当然也不是说xml中就⼀定不能存图⽚)。oracle数据库表结构怎么看
不过我现在觉得xml字段还是要的,作为辅助存储⼿段,因为毕竟未来查询起来可能会更⽅便些,然后结合“观察模式”也就是类似上图的⽅法作为主要的存储⼿段,虽然有⼀些冗余,结合我的使⽤
NVelocity 解析 PowerDesigner 的cdm⽂件 ,⼯作量也不会太⼤。
再研究研究看看。
下⾯是⼀个不定字段数⽬的数据结构的解决办法是⽤了⼀个模板表
CREATETABLE[dbo].[ProductAttributeDataTypes]([DataTypeId][int]NOTNULL,[Description][varchar]
(30) COLLATE SQL_Latin1_General_CP1_CI_ASNOTNULL)CREATETABLE[dbo].[ProductAttributeListItems]([LookupListId] [int]NOTNULL,[ListItemId][int]IDENTITY(1,1)NOTNULL,[DisplayName][varchar]
(50) COLLATE SQL_Latin1_General_CP1_CI_ASNOTNULL)CREATETABLE[dbo].[ProductAttributeLookupLists] ([LookupListId][int]IDENTITY(1,1)NOTNULL,[Name][varchar]
(80) COLLATE SQL_Latin1_General_CP1_CI_ASNOTNULL)CREATETABLE[dbo].[ProductAttributeTemplateCategories] ([PATCategoryId][int]IDENTITY(1,1)NOTNULL,[Name][varchar](50) COLLATE SQL_Latin1_General_CP1_CI_ASNOTNULL, [DisplayName][varchar](255) COLLATE SQL_Latin1_General_CP1_CI_ASNOTNULL)CREATETABLE[dbo]. [ProductAttributeTemplates]([AttributeTemplateId][int]IDENTITY(1,1)NOTNULL,[Name][varchar]
(50) COLLATE SQL_Latin1_General_CP1_CI_ASNOTNULL,[DataType][int]NOTNULL,[LookupListId][int]NULL, [PATCategoryId][int]NOTNULL,[CustomerHelp][varchar](4000) COLLATE SQL_Latin1_General_CP1_CI_ASNULL,
[DisplayName][varchar](255) COLLATE SQL_Latin1_General_CP1_CI_ASNULL)CREATETABLE[dbo].
[ProductAttributeValues]([ProductId][int]NOTNULL,
[AttributeTemplateId][int]NOTNULL,[valueInt][int]NULL,[valueStr][varchar]
(255) COLLATE SQL_Latin1_General_CP1_CI_ASNULL,[valueMemo][text]COLLATE SQL_Latin1_General_CP1_CI_ASNULL, [valueBool][bit]NULL)CREATETABLE[dbo].[ProductListItems]
([ProductListId][int]NOTNULL,[ProductId][int]NOTNULL, [ItemDescription][varchar](80) COLLATE SQL_Latin1_General_CP1_CI_ASNULL,[DisplaySequence][int]NOTNULL)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。