在数据库中存储默认值的最佳方法是什么?

9
我有几个表格,例如BuyersShopsBrandsMoney_Collectors等。
每张表都有一个默认值,例如默认的BuyerDavid,默认的ShopEbay等等。
我想将这些默认值保存在数据库中(以便用户可以更改它们)。
我考虑为每个表格添加一个is_default列,但似乎不太有效,因为每个表格中只有一行可以是默认值。
然后我想最好的方法是创建一个Defaults表格,其中包含所有默认值。该表将有1行和N列,其中N是默认值的数量:
Defaults table:

buyer      shop      brand      money_collector
-----      ----      -----      ---------------
David      Ebay      Dell       NULL   (no default value)

但是,这似乎不是最好的方法,因为当添加新的默认值时,表结构会发生变化。

存储默认值的最佳方法是什么?


3
首先,"默认值"是什么意思?其次,每张表只有一个默认值还是每位用户在每张表中都有一个默认值?当你说"以便用户可以更改它们"时,这似乎意味着每个用户都会有一组默认值。还是说你是指管理员用户可以更改默认值?最后,为什么你反对添加一个"is_default"列?这会有什么问题吗? - Stephanie Page
在我的情况下,每个表存储选择框中所有可能的值。每个选择框都有一个默认值(如果没有默认值,则为nil)。我不关心用户。假设只有一个用户(如管理员)可以更改默认值。关于“is_default”列:假设有50家商店(具有50个可能值的选择框)。在这种情况下,为了存储默认商店,您需要50个布尔字段,而不是1个。换句话说,我不想浪费空间。在保存数据到数据库时,我不应该担心空间问题吗? - Misha Moroshko
你希望默认设置如何工作?是针对用户界面,使商店选择框默认为Ebay吗?还是针对数据库后端,如果用户没有选择商店,则将Ebay存储为商店? - Vince Bowdren
5个回答

20

请明确一点。

最好的方法是在每个表上都有一个下拉列表来源列。

以下是原因...

"我不应该担心在数据库中保存数据时的空间吗?"

简单的答案是不用。更长的答案是你应该担心的是性能。如果专注于空间,你会做出非常糟糕的事情。

如果空间是一个问题,你会做出以下糟糕的事情:

  • 你会把意义埋入主键中,即智能键。
  • 你会尝试在一个列中存储多个值。
  • 你将过少地建立索引。
  • (毫无疑问,我们可以列出50种节省空间的糟糕实践)

假设有50家商店(下拉框有50个可能的值)。在这种情况下,要存储默认商店,您需要50个布尔字段,

好吧,这是一个布尔列。它存在于每一行中。

让我问你这个问题。如果你创建了一个只有1个日期列并插入了1行的表,你会使用多少磁盘空间?

如果你说7或8个字节,那么你错了大约1000倍。

磁盘空间的最小单位是块。块通常为8kb(可以小至2kb,大至32kb,在一般情况下(这里不要挑剔,实际限制并不重要)

假设你有8kb的块,那么你的1列、1行表将占用8Kb。如果你插入另外999行,它仍将占用8KB。(再次说明,每个块和每行都有开销-这只是一个例子)

因此,在你的包含50个商店名称的查找表中,添加50个字节到表的大小强制你从1个块扩展到2个的可能性微乎其微,完全无关紧要。

另一方面,你的默认表肯定会占用至少一个额外的块。但对性能的最严重影响是,你的调用填充下拉列表将需要两次往返数据库的操作,一次获取列表,一次获取默认值。(是的,你可能可以在一次操作中完成,但还是这样吧)

所以你节省了零空间,但网络流量翻了一倍。

你明白我的意思吧。


停止担心空间的另一个关键原因是你放弃了清晰度。想象一下你将雇用运行此应用程序的开发人员。当他加入团队并查看数据库时,想象两种情况。

  1. 有一个名为Default_value的布尔型列。
  2. 有一个没有与任何东西相关联的表,名为Default_Values。

您要求他建立一个带下拉列表的新表单,用于“商店”。

在第一种情况下,他找到了store表,将下拉列表连接到该表的简单查询,并使用default_value字段选择初始值。

在第二种情况下,如果没有一些训练,他怎么会知道要寻找一个单独的表呢?也许他会看到这个表,但当你雇佣人员时,你的数据模型现在已经拥有数百个表。

再次强调一下,这有点刻意,但要点很显著。数据库中的清晰度非常值得每行一个字节的代价。


技术方面

我不是MySQL专家,但在Oracle中,最后一行的空列不占用额外的空间。在Oracle中,我会使用Varchar2(1),并让'T' = Default,其他保持为空。这将总共只使用 1 个额外字节,而不是每行都占用一个字节。在MySQL中,您可以单独提出这个问题,如果无法通过Google搜索答案。

但是开始担心这个问题的时间是在有数百万行数据的时候,而不是几百行。任何用于下拉列表的表都不会足够大,以至于需要开始担心额外的字节。


在MySQL中,NULL VARCHAR(n <= 255)占用一个字节。TINYINT(在MySQL中是BOOLEAN的同义词)同样可以胜任。 - Mchl
你在回复评论而不是问题。 - Lightness Races in Orbit
谢谢 Mchl。同意。问题是什么是存储默认值的最佳方式,而且它与列在同一表中。评论淘汰了其中的一个解决方案(最佳解决方案),理解 OP 反对该解决方案对于提供坚实的答案/解释至关重要。 - Stephanie Page

1
如果您创建一个XML,然后将该XML存储在XML列中的表中,会怎样呢?XML列将包含XML,而XML可以具有表的标签和默认值的子节点。

0
您可以创建一个目录表(一种元数据表),其中包含所需表列的字符串默认值。然后,您可以使用convert函数获取适当的值。以下是一个示例表定义(使用了Transact-SQL):
create table dbo.cat_default_values
(
    id_column       varchar(30)    not null,
    id_table        varchar(30)    not null,    
    datatype        varchar(30)    not null,    
    value           varchar(100)   not null,    
    f_creation      datetime       not null,
    usr_creation    char(8)        null,    
    primary key  clustered  (id_column, id_table)
)    

declare @defaultValueInt int,
        @defaultValueVarchar varchar(30)

select @defaultValueInt = convert(int, value) 
    from cat_default_values where id_column = "defColumInteger" and id_table = "table1"

select defaultValueVarchar = value 
    from cat_default_values where id_column = "defColumVarchar" and id_table = "table1"

0
你应该创建一个有两列和n行的表格。
Defaults table:
buyer, David
shop, Ebay,
brand, Dell

这样你就可以添加新的值而不必更改表结构


1
但是,如果一些表格包含数字或布尔值呢? - Misha Moroshko
1
这是一个经典的EAV。在这种情况下可能并不可怕,但它是反模式,应该避免使用。 - Stephanie Page
2
就像我之前所说的,如果只是用一个默认表格,这看起来就像Windows注册表...它只是一个键值对列表。在这种情况下,使用EAV风格的表格并不可怕。但是,由于我知道很多程序员的想法;一旦你做了一次,你会把它放在更多不应该放置的地方。;-) - Stephanie Page
1
当A = const = 'defaultValue'时,它几乎不是EAV。 :) EAV在第一眼看起来确实很诱人,但一旦深入其中,就会变得可怕。它有其用途,但我同意如果可能的话应该避免使用它(只是不要为了更糟糕的解决方案而放弃它)。在这种特定情况下,键值表应该非常适合。 - Mchl
它是不受控制的键值存储,而且非常丑陋。 - PerformanceDBA
显示剩余4条评论

0

你试图存储的不是元数据信息。首先,我不会发明一个外部数据存储来存储这些数据(还需要额外的代码)。

我假设你有一个PK序列生成逻辑(在你的控制下)。我将分配一个魔术数字x,并在每个表中插入一条记录,_id = x作为默认值。因此,如果您想向用户显示默认值,可以以统一的方式处理查询,或者在插入时在应用程序逻辑中处理。好处是,您随时可以访问默认值,而无需编写任何额外的逻辑,并且维护表的默认值的逻辑可以使用相同的代码进行维护(模板;)(从W3c从使用DTD建模XML的模式信息中学到的教训。)

唯一的问题是,这个逻辑应该通过一些广泛的文档来明确,或者可以通过使用触发器来强制执行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接