如何构建一个完全可自定义的应用程序(也称为数据库),而不会失去性能/良好的设计?

时间:2009-06-04 15:45:53

标签: php python performance database-design postgresql

我在我的Web应用程序的完整restyle的开头,我对一个可靠,查询性能良好的数据库设计有疑问,同时完全可以由用户定制(用户不会自定义数据库结构,但应用程序的功能。)

所以,我的实际情况是,例如,一个简单的用户表:

id | name | surname | nickname | email       | phone
1  | foo  | bar     | foobar   | foo@bar.com | 99999

多数民众赞成。

但是,假设我的一位客户希望为一位特定用户提供2个电子邮件地址或电话号码。

直到现在,我过去只是在users表中添加列来解决这个问题:

id | name | surname | nickname | email       | phone | email_two    | phone_two
1  | foo  | bar     | foobar   | foo@bar.com | 99999 | foo@bar.net  | 999998

但我不能用新应用程序的版本使用这种方式..之后我会喜欢喝莫吉托,不喜欢costumer的编辑结构调用:)

所以,我认为一个解决方案,人们可​​以用另一个表来定义海关领域:

id | table_refer | type_field | id_object | value
1  | users       | phone      | 1         | 999998
2  | users       | email      | 1         | foo@bar.net

保持用户表不变。

但这种方式有两个问题:

  1. 据我所知,没有可能以这种方式使用foreigns键,如果我自动删除1个用户,则在级联中删除外键,所有第二个表中具有'table_refer'值= users的行id_object = users.id。当然,我可以使用一些触发功能,但我会失去一些可靠性。
  2. 当我需要查询数据库时,请检索匹配'foo@bar.net'的用户,我还要检查所有... hem .. option_table,这将使我的代码复杂,不太可靠,有很多连接的混乱......假设用户表不是'option_table'唯一'扩展',似乎是灰色视图。
  3. 我的目标是让我的客户为应用程序中的几乎所有对象(用户,项目,发票,打印视图,照片,新闻等等)添加尽可能多的自定义字段,假设大多数这些表的分区将被分割(在2个表中拆分,具有3个表和继承层次结构)。

    你认为我的方式可以很好,你知道其他更好的,还是我犯了大错? 拜托,现在每个建议都是黄金!

    编辑

    我正在寻找的东西可以通过wordpress博客中的'articles-custom-fields'进行简化。 我的目标是让用户定义他需要的新字段,例如,如果我的用户表是上面的那个,并且客户需要一个我没有阻止的字段,比如网站网址,他必须能够以动态方式添加它,不需要编辑数据库结构,只需编辑数据。

    我认为2°表(每个对象的maibe 1)可以是一个很好的解决方案,但我还在等待更好的方法!

5 个答案:

答案 0 :(得分:4)

正如我在Answer中提到的类似问题,“数据库设计很难。”您将不得不做出哪个更适合您的决定,规范化表并将电话号码和电子邮件地址放入他们自己的表中,使用相关联的JOIN来检索数据,以及额外的参考努力完整性,或者在表中包含一些 n 电子邮件和电话字段,以及需要的“数据混乱”。

数据库设计总是一系列的权衡。您需要查看所有角度,可能会提出一些原型并进行一些分析等。没有“One True Answer™”。

答案 1 :(得分:1)

您提出的模型由两种数据库模式组成:entity-attribute-value tablepolymorphic association

实体属性值在性能和数据完整性部门都有一些非常大的问题。如果您不需要访问查询中的其他属性,则可以将属性值映射序列化为某些标准序列化(JSON,XML)中的文本字段。从数据库设计的角度来看,这不是“纯粹的”,但考虑到你了解权衡,可能是一个很好的实用选择。在postgres上,如果仅限字符串值的限制是可接受的,您还可以使用hstore contrib模块存储键值对以使其在查询中可用。

对于多态关联,您可以通过引入关联表来获得参照完整性:

users                attrib_assocs       custom_attribs
-----                -------------       --------------
attrib_assoc_id -->  id             <--  assoc_id
...                  entity_type         field
                                         value

为了获得更多的完整性,还要将entity_type添加到主键和相应的外键以及在users表上将entity_type等于'user'的检查约束。

答案 2 :(得分:0)

如果你这样做,你的所有查询都必须加入并使用table_refer列,这会破坏性能,简化查询,硬查询非常困难。

如果您想要多封电子邮件,请将电子邮件拆分到另一个表格,这样您就可以拥有多行。

答案 3 :(得分:0)

您可以根据需要设计应用程序以使用AJAX等请求其他数据(例如用户的电子邮件列表)。在那些高度可定制且丰富的应用程序中,通常您无需显示所有数据 - 只需一个类别。

要存储自定义记录,您可以创建表field_types(id, name, datatype)和表custom_fields(user_id, field_type_id, value),然后选择这样的smth:

SELECT * FROM custom_fields WHERE user_id=XXX AND field_type_id IN (X,Y,Z)

现在您可以在1个快速查询中检索数据,将字段拆分为类别,并使用您的代码按照各自的数据类型解析它们的值,而不会出现性能问题。

答案 4 :(得分:0)

我不确定postgresql的具体细节,但是如果你想在数据库中使用高度可自定义的数据结构,你真的不想搜索,那么s erializing the data to a LOB是一个选项。

实际上,这是ASP.NET默认使用Personalization的方式,即按用户设置。

如果您因任何原因希望搜索字段,我不建议使用此方法。