在设计用于存储用户设置的表时,以下哪个选项(如果有)被认为是最佳做法?
(选项1)
USER_SETTINGS
-Id
-Code (example "Email_LimitMax")
-Value (example "5")
-UserId
(选项2)
为每个设置创建一个新表格,例如,通知设置需要您创建:
"USER_ALERT_SETTINGS"
-Id
-UserId
-EmailAdded (i.e true)
-EmailRemoved
-PasswordChanged
...
...
"USER_EMAIL_SETTINGS"
-Id
-UserId
-EmailLimitMax
....
(选项3)
"USER"
-Name
...
-ConfigXML
答案 0 :(得分:66)
其他答案已经清楚地概述了各种选择的利弊。
我相信你的选项1(属性包)是大多数应用程序的最佳整体设计,特别是如果你建立一些保护措施来防止打包袋的缺点。
请参阅以下ERD:
在上面的ERD中,USER_SETTING
表与OP非常相似。区别在于,不是varchar Code
和Value
列,此设计具有FK到SETTING
表,该表定义了允许的设置(代码)和值的两个互斥列。一个选项是varchar字段,可以接受任何类型的用户输入,另一个是FK到合法值表。
SETTING
表还有一个标志,指示用户设置是应该由FK还是由无约束的varchar输入定义。您还可以向data_type
添加SETTING
,告诉系统如何编码和解释USER_SETTING.unconstrained_value
。如果您愿意,还可以添加SETTING_GROUP
表以帮助组织用户维护的各种设置。
此设计允许您根据设置来制定规则。这样既方便,灵活又易于维护,同时避免了免费使用。
编辑:更多细节,包括一些示例......
请注意,上面的ERD已经增加了更多列详细信息(SETTING上的范围值和ALLOWED_SETTING_VALUE上的列)。
以下是一些示例记录。
SETTING:
+----+------------------+-------------+--------------+-----------+-----------+
| id | description | constrained | data_type | min_value | max_value |
+----+------------------+-------------+--------------+-----------+-----------+
| 10 | Favourite Colour | true | alphanumeric | {null} | {null} |
| 11 | Item Max Limit | false | integer | 0 | 9001 |
| 12 | Item Min Limit | false | integer | 0 | 9000 |
+----+------------------+-------------+--------------+-----------+-----------+
ALLOWED_SETTING_VALUE:
+-----+------------+--------------+-----------+
| id | setting_id | item_value | caption |
+-----+------------+--------------+-----------+
| 123 | 10 | #0000FF | Blue |
| 124 | 10 | #FFFF00 | Yellow |
| 125 | 10 | #FF00FF | Pink |
+-----+------------+--------------+-----------+
USER_SETTING:
+------+---------+------------+--------------------------+---------------------+
| id | user_id | setting_id | allowed_setting_value_id | unconstrained_value |
+------+---------+------------+--------------------------+---------------------+
| 5678 | 234 | 10 | 124 | {null} |
| 7890 | 234 | 11 | {null} | 100 |
| 8901 | 234 | 12 | {null} | 1 |
+------+---------+------------+--------------------------+---------------------+
从这些表中,我们可以看到可以确定的一些用户设置是“收藏颜色”,“项目最大限制”和“项目最小限制”。最喜欢的颜色是字母数字的选择列表。项目最小和最大限制是数字,并设置了允许的范围值。 SETTING.constrained
列确定用户是从相关的ALLOWED_SETTING_VALUE
中挑选还是需要输入USER_SETTING.unconstrained_value
。允许用户使用其设置的GUI需要了解要提供的选项以及如何强制执行SETTING.data_type
和min_value
以及max_value
限制(如果存在)。
使用此设计,您可以驱动允许的设置,包括足够的元数据,以对用户选择(或输入)的值强制执行一些基本的约束/健全性检查。
编辑:示例查询
以下是使用上述数据列出给定用户ID的设置值的示例SQL:
-- DDL and sample data population...
CREATE TABLE SETTING
(`id` int, `description` varchar(16)
, `constrained` varchar(5), `data_type` varchar(12)
, `min_value` varchar(6) NULL , `max_value` varchar(6) NULL)
;
INSERT INTO SETTING
(`id`, `description`, `constrained`, `data_type`, `min_value`, `max_value`)
VALUES
(10, 'Favourite Colour', 'true', 'alphanumeric', NULL, NULL),
(11, 'Item Max Limit', 'false', 'integer', '0', '9001'),
(12, 'Item Min Limit', 'false', 'integer', '0', '9000')
;
CREATE TABLE ALLOWED_SETTING_VALUE
(`id` int, `setting_id` int, `item_value` varchar(7)
, `caption` varchar(6))
;
INSERT INTO ALLOWED_SETTING_VALUE
(`id`, `setting_id`, `item_value`, `caption`)
VALUES
(123, 10, '#0000FF', 'Blue'),
(124, 10, '#FFFF00', 'Yellow'),
(125, 10, '#FF00FF', 'Pink')
;
CREATE TABLE USER_SETTING
(`id` int, `user_id` int, `setting_id` int
, `allowed_setting_value_id` varchar(6) NULL
, `unconstrained_value` varchar(6) NULL)
;
INSERT INTO USER_SETTING
(`id`, `user_id`, `setting_id`, `allowed_setting_value_id`, `unconstrained_value`)
VALUES
(5678, 234, 10, '124', NULL),
(7890, 234, 11, NULL, '100'),
(8901, 234, 12, NULL, '1')
;
现在DML提取用户的设置:
-- Show settings for a given user
select
US.user_id
, S1.description
, S1.data_type
, case when S1.constrained = 'true'
then AV.item_value
else US.unconstrained_value
end value
, AV.caption
from USER_SETTING US
inner join SETTING S1
on US.setting_id = S1.id
left outer join ALLOWED_SETTING_VALUE AV
on US.allowed_setting_value_id = AV.id
where US.user_id = 234
请参阅SQL Fiddle。
答案 1 :(得分:7)
选项1(如上所述,“属性包”)易于实施 - 前期分析非常少。但它有一堆缺点。
如果要限制UserSettings.Code的有效值,则需要一个辅助表来显示有效标记列表。所以你要么(a)没有对UserSettings.Code进行验证 - 你的应用程序代码可以转储任何值,错过捕获错误的机会,或者你必须在新的有效标签列表上添加维护。
UserSettings.Value可能有一个字符串数据类型,以容纳可能进入它的所有不同值。因此,您丢失了真正的数据类型 - 整数,布尔值,浮点数等,以及RDMBS在插入不正确的值时将执行的数据类型检查。再一次,你给自己买了一个潜在的质量保证问题。即使对于字符串值,您也无法约束列的长度。
您无法根据代码在列上定义DEFAULT值。因此,如果您希望EmailLimitMax默认为5,则无法执行此操作。
同样,您不能在“值”列上放置CHECK约束以防止无效值。
属性包方法失去了对SQL代码的验证。在命名列方法中,如果Blah不存在,则显示“从UserSettings中选择Blah,其中UserID = x”的查询将获得SQL错误。如果SELECT位于存储过程或视图中,则在代码进入生产之前应用proc / view - way时将出现错误。在属性包方法中,您只需获得NULL。因此,您丢失了数据库提供的另一个自动QA功能,并引入了可能未检测到的错误。
如上所述,查找条件适用于多个标签的UserID的查询变得更难编写 - 对于每个被测试的条件,它需要一个连接到表中。
不幸的是,Property Bag邀请应用程序开发人员将新代码粘贴到属性包中,而不分析它将如何在其余应用程序中使用。对于大型应用程序,它会成为“隐藏”属性的来源,因为它们没有正式建模。这就像使用纯标记值而不是命名属性来创建对象模型:它提供了一个转义阀,但是您缺少编译器为强类型命名属性提供的所有帮助。或者喜欢在没有模式验证的情况下进行生产XML。
列名方法是自我记录的。表格中的列列表告诉任何开发人员可能的用户设置是什么。
我用过物业袋;但只是作为一个逃生阀,我经常后悔。我从来没有说过“哎呀,我希望我已经把这个明确的专栏作为财产包。”
答案 2 :(得分:7)
考虑这个简单的例子。
如果您有2个表, UserTable (包含用户详细信息)和 设置表(包含设置详细信息)。然后创建一个新表 UserSettings ,用于关联UserTable和SettingsTable,如下所示
希望您能从此示例中找到正确的解决方案。
答案 3 :(得分:4)
每个选项都有它的位置,选择取决于您的具体情况。我正在比较下面每个选项的优缺点:
选项1:优点:
选项1:缺点
选项2:优点
选项2:缺点
答案 4 :(得分:3)
难以评估"最佳"因为它取决于您要运行的查询类型。
选项1(通常称为"属性包","名称值对"或" entity-attribute-value"或EAV)使其易于存储您之前不知道其架构的数据。但是,它使得运行常见的关系查询变得困难 - 有时甚至是不可能的。例如,假设运行等效的
select count(*)
from USER_ALERT_SETTINGS
where EmailAdded = 1
and Email_LimitMax > 5
这会很快变得非常复杂,特别是因为您的数据库引擎可能无法以数字方式比较varchar字段(因此">>"可能无法按预期方式工作)。
我计算出您要运行的查询,并查看哪种设计最适合这些查询。如果您只需要检查个人用户的限制,那么属性包就可以了。如果您必须报告所有用户,则可能不会。
JSON或XML也是如此 - 它可以存储单个记录,但更难以查询或报告所有用户。例如,想象一下搜索电子邮件地址的配置设置" bob@domain.com" - 这将需要搜索所有XML文档以查找节点"电子邮件地址"。