繁体   English   中英

在SQL Server数据库中使用单行配置表。馊主意?

[英]Using a Single Row configuration table in SQL Server database. Bad idea?

在开发购物车应用程序时,我发现我需要根据管理员的偏好和要求保存设置和配置。 此信息可以是公司信息,运输帐户ID,PayPal API密钥,通知首选项等。

创建一个表来在关系数据库系统中存储单行似乎非常不合适。

存储此信息的适当方法是什么?

注意:我的DBMS是SQL Server 2008,编程层是用ASP.NET实现的(在C#中)。

我过去曾做过两种方式 - 单行表和键/值对表 - 每种方法都有正面和负面。

单行

  • positive:值以正确的类型存储
  • 积极的:代码处理更容易(由于上述原因)
  • positive:可以单独为每个设置指定默认值
  • 否定:添加新设置需要更改架构
  • 否定:如果有很多设置,表格会变宽

键/值对

  • 肯定:添加新设置不需要更改架构
  • positive:表模式很窄,额外的行用于新设置
  • 否定:每个设置都有相同的默认值(null / empty?)
  • 否定:一切都必须存储为字符串(即.nvarchar)
  • 否定:在处理代码中的设置时,您必须知道设置的类型并进行转换

单行选项是迄今为止最容易使用的选项。 这是因为您可以在数据库中以正确的类型存储每个设置,而不必在代码中存储设置的类型以及它们的查找键。

我关注使用这种方法的一件事是在“特殊”单行设置表中有多行。 我通过(在SQL Server中)克服了这个问题:

  • 添加一个默认值为0的新位列
  • 创建检查约束以确保此列的值为0
  • 在位列上创建唯一约束

这意味着表中只能存在一行,因为位列必须具有值0,但由于唯一约束,只能有一行具有该值。

您应该创建一个表,其中包含信息类型和信息值的列(至少)。 这样,您可以避免每次添加新信息时都必须创建新列。

单排工作正常; 它甚至会有很强的类型:

show_borders    bit
admin_name      varchar(50)
max_users       int

一个缺点是它需要模式更改( alter table )来添加新设置。 一种替代方法是规范化,最终得到如下表:

pref_name       varchar(50) primary key
pref_value      varchar(50) 

这有弱类型(一切都是varchar),但添加一个新设置只是添加一行,你可以只使用数据库写访问。

就个人而言,如果可行,我会把它存储在一行中。 是否将它存储在SQL表中? 可能,但这样做并没有真正的危害。

正如您所猜测的那样,除了最简单的情况之外,将所有配置参数放在一行中有许多缺点。 这是一个坏主意......

存储配置和/或用户偏好类型的信息的便利方式是XML 许多DBMS支持XML数据类型。 XML语法允许您随着此配置的发展而消耗描述配置的“语言”和结构。 XML的一个优点是它对层次结构的隐式支持,允许例如存储配置参数的小列表,而不必使用带编号的后缀来命名它们。 XML格式的一个可能的缺点是搜索和修改这些数据并不像其他方法那样简单(没有什么复杂,但不是那么简单/自然)

如果您希望更接近关系模型实体 - 属性 - 值模型可能就是您所需要的,因此各个值存储在通常如下所示的表中:

EntityId     (foreign key to the "owner" of this attribute)
AttributeId  (foreign key to the "metadata" table where the attribute is defined)
StringValue  (it is often convenient to have different columns of different types
IntValue      allowing to store the various attributes in a format that befits 
              them)

因此,AttributeId是表的外键,其中定义了每个可能的属性(在您的情况下为“配置参数”),比如说

AttributeId  (Primary Key)
Name
AttributeType     (some code  S = string, I = Int etc.)
Required          (some boolean indicating that this is required)
Some_other_fields   (for example to define in which order these attributes get displayed etc...)

最后,EntityId允许您识别“拥有”这些不同属性的某个实体。 在您的情况下,如果您只有一个要管理的配置,它可能是UserId,甚至只是隐含的。

除了允许可能的配置参数列表随着应用程序的发展而增长,EAV模型将“元数据”(即属于属性本身的数据)放置在数据表中,从而避免了常见的所有列名称的硬编码当配置参数存储在单行中时。

在规范化方法中添加新配置参数时,您当然不必更改架构,但您仍可能更改代码以处理新值。

在您的部署中添加“alter table”似乎并不是单行方法的简单性和类型安全性的重大权衡。

Key和Value对类似于.Net App.Config,它可以存储配置设置。

因此,当您想要检索您可以执行的值时:

SELECT value FROM configurationTable
WHERE ApplicationGroup = 'myappgroup'
AND keyDescription = 'myKey';

执行此操作的常用方法是使“属性”表与属性文件相似。 在这里,您可以存储所有应用程序常量,或者不存储您需要拥有的常量内容。

然后,您可以根据需要从此表中获取信息。 同样,当您发现还有其他要保存的设置时,可以将其添加进来。以下是一个示例:

property_entry_table

[id, scope, refId, propertyName, propertyValue, propertyType] 
1, 0, 1, "COMPANY_INFO", "Acme Tools", "ADMIN"  
2, 0, 1, "SHIPPING_ID", "12333484", "ADMIN"  
3, 0, 1, "PAYPAL_KEY", "2143123412341", "ADMIN"   
4, 0, 1, "PAYPAL_KEY", "123412341234123", "ADMIN"  
5, 0, 1, "NOTIF_PREF", "ON", "ADMIN"  
6, 0, 2, "NOTIF_PREF", "OFF", "ADMIN"   

通过这种方式,您可以存储您拥有的数据,以及明年您将拥有但尚未了解的数据:)。

在此示例中,您的范围和refId可用于后端的任何内容。 因此,如果propertyType“ADMIN”的范围为0 refId 2,那么您就知道它是什么偏好。

当有一天你需要在这里存储非管理员信息时,属性类型就会出现。

请注意,您不应该以这种方式存储购物车数据,也不应该查找。 specific, then you can certainly use this method. 但是,如果数据是特定于 ,那么您当然可以使用此方法。

, you'd use a table like this. 例如:如果要存储 ,则可以使用这样的表。 这样,当您需要升级应用程序时,可以检查属性表以查看客户端具有的软件版本。

关键是你不想将它用于与购物车有关的东西。 在明确定义的关系表中保持业务逻辑。 属性表仅用于系统信息。

我不确定单行是配置的最佳实现。 你可能最好每个配置项有两行(configName,configValue),尽管这需要将所有值都转换为字符串并返回。

无论如何,使用单行进行全局配置没有任何害处。 将其存储在DB(全局变量)中的其他选项更糟糕。 您可以通过插入第一个配置行来控制它,然后禁用表上的插入以防止多行。

您可以在不进行转换的情况下执行键/值对,方法是为每个主要类型添加一列,并使用一列告知数据所在的列。

所以你的表看起来像:

id, column_num, property_name, intValue, floatValue, charValue, dateValue
1, 1, weeks, 51, , ,
2, 2, pi, , 3.14159, , 
3, 4, FiscYearEnd, , , , 1/31/2015
4, 3, CompanyName, , , ACME, 

它使用了更多的空间,但最多只使用了几十个属性。 您可以使用column_num值之外的case语句来拉/加入右侧字段。

对不起,我来了,是以后。 但无论如何,我所做的是简单而有效的。 我只是创建一个包含三()列的表:

ID - int(11)

name - varchar(64)

价值 - 文本

在创建新的配置列,更新它或读取之前我所做的是序列化“值”! 这种方式我肯定的类型(嗯,PHP是:))

例如:

B:0; 是为了B OOLEAN(

B:1; 是为了B OOLEAN( 真的

I:1988; 是为了新台币

S:5: “卡迪尔”; 用于5个字符长度的S TRING

我希望这有帮助 :)

将键列作为varchar,将值列作为JSON。 1是数字,而"1"是字符串。 truefalse都是布尔值。 你也可以拥有对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM