6

好吧,我不是数据库架构师,所以这个问题完全来自软件开发人员的角度。我目前正在努力获得一个简单的设置数据库,并且想知道在 SQL Server 中存储不同类型的最有效、最高效的方式是什么。例如,SettingA 可以具有布尔值、整数值、浮点值或字符串值。什么是存储该数据的最有效方式和最高效的检索方式。

  1. 将所有类型存储在一个字符串字段中,并让应用程序服务器将其转换为正确的值。

  2. 对不同类型有不同的字段,并让应用程序服务器查看哪个字段不为空并使用它(BooleanValue、StringValue、IntValue、FloatValue,并且只有一个为非空且有值)

  3. 根据类型将设置规范化到不同的表中,并且仅在使用该类型时才向表中添加值。(四个表 BooleanValues、StringValues、IntValues、FloatValues 与 Settings 表的外键)。然后 SP 将返回具有记录的任何表。

性能绝对是我的第一关注点,但空间问题紧随其后。

4

4 回答 4

1

将设置存储在 XML 列中。

我的意思是单个 XML 设置文档中的项目的所有设置,以便可以一次性检索和更新它们。提供模式以降低存储成本并优化查询。然后数据库将知道设置值的数据类型。

如果您希望查询具有特定设置值的所有项目,您可以使用 XML 索引和/或 XQuery 查询。

我创建了一个 SQLFiddle 来展示它的样子: http ://sqlfiddle.com/#!6/49c34/1

至于索引,请看一下XML Indexes,特别是Selective XML Indexes

选择性 XML 索引功能允许您仅将 XML 文档中的某些路径提升为索引。在创建索引时,会评估这些路径,并将它们指向的节点分解并存储在 SQL Server 的关系表中。此功能使用 Microsoft Research 与 SQL Server 产品团队合作开发的高效映射算法。该算法将 XML 节点映射到单个关系表,并在仅需要适度存储空间的情况下实现卓越的性能。

如果设置通常一起插入和检索,我希望这表现得很好,甚至比每个设置使用一个表行更好。在这种情况下,将它们撕成位,将位分散到表行中,只是在您检索它们时检索并再次将它们粘回来是没有意义的。

如果您希望查询几个特定设置或这些特定设置的条件,选择性 XML 索引将帮助您实现此目的。

何时需要注意:

  • 如果项目之间的设置差异很大。因为它们将没有共享模式,并且设置文档所需的存储空间变得很大,可能太大。
  • 如果您需要对设置文档的不同元素进行广泛的查询才能正常执行。因为您可能最终需要大量的索引空间。
  • 如果部分设置比其他设置更频繁地更改,您可能需要将它们分开并单独存储。否则,您可能会在每次旋转一个位时更新整个设置文档。
于 2013-04-03T16:16:51.843 回答
1

我想给出以下建议,专注于高级设计。

首先,看起来你的系统是LOB(Line of business system),而不是数据仓库,所以,当然如果你不同的业务实体,你应该按照NF规范化它们,通常,第三个NF就足够了。

对于您的具体问题,您有一个字段 [SittingA],它可以有 4 种不同的可能数据类型,我认为您不应该将它们规范化为不同的列或表,因为它只有一个属性,一个归档,你没有不想添加额外的业务逻辑来控制它写入不同的列或表,并且在查询它时,必须确定在哪里查询。

您可以将它们存储在具有 Varchar 数据类型的一列中,但创建一个计算列,对 varchar 列中的值进行散列,在计算列上创建索引(散列索引)。您使用存储过程来完成哈希约定和查询。

这可以使您的逻辑简单而整洁。

如果您还有其他问题或疑虑,请更新您的问题或发表评论。

于 2013-04-03T16:22:17.450 回答
1

解决方案 #2:
您可以使用 Isnull 链执行类似的操作,以根据某些主键关联将信息拉回。在不知道您的实现的情况下,我不知道这将是多么愚蠢的建议,但这是一种以所需格式将输入存储在后端的方法。

/*
        Create  Table #test 
                (
                    tID         Int Identity, 
                    StringVal   Varchar(100), 
                    FloatVal    Float, 
                    BoolVal     Bit, 
                    IntVal      Int
                )
*/

Declare @bah Varchar(100)

Set     @bah = 'ValuesToTest'

If      IsNumeric(@bah) = 0
Begin
        If      @bah In ('true','false') --Went with this assumption otherwise you'd get confused between 1 bool and 1 int
        Begin
                Insert  #test (BoolVal)
                Select  Case
                        When    @bah = 'true' Then 1
                        Else    0
                        End
        End
        Else
        Begin
                Insert  #test (StringVal)
                Select  @bah
        End
End
Else    If Floor(Convert(Money,@bah)) <> Ceiling(Convert(Money,@bah)) --Compensate for IsNumeric interpretation of money
Begin
        Insert  #test (FloatVal)
        Select  Convert(Float,Convert(Money,@bah))
End
Else
Begin
        Insert  #test (IntVal)
        Select  Convert(Int,@bah)
End

您的值列的基线将是 1 个字节以允许可空值,1 个字节用于位列,4 个字节用于 int 列,4 个字节用于浮点数和 2 个字节用于 varchar(对于变量长度存储)所以看起来您正在查看 15 个字节的基线。

如果它是位或整数(15 字节)将是您的存储需求,如果它是双精度,则它可能会增加 4 个字节,如果精度为 25 或更高,并且 varchar 会增加等于长度的字节数正在存储的记录。因此,如果您改为使用不可为空的 varchar,则每条记录最多可为您节省 12 个字节(可变长度存储最少为 2 个字节,单个字符值最少为 1 个字节)。因此,对于 1,000,000 条记录,您正在查看大约 11.5 MB 的额外数据存储空间。

但是,如果您要根据值查找主键,则使用此解决方案可能会更快,因为在 varchar 上查找位、int 或 float 索引值会更快,所以如果在执行您的查找后,您将知道要使用哪种数据类型,走这条路会更快,因为只要您的列被索引,您就可以忽略所有在不同列中具有值的 Null。如果您要根据主键获取值,请使用单个 varchar 列,因为好处可以忽略不计。

于 2013-04-03T17:39:19.503 回答
0

假设数据库服务器和应用程序服务器具有可测量的(> 1 毫秒)延迟,我会选择选项 2。这里有两件事在起作用:一起存储在单行中的数据更易于查询,访问速度更快. 数据库以块的形式组织存储,并且在同一行中(并且小于块大小,通常为 4KB)意味着更快的访问。

现在,您可能需要为设置设置一个带有主键的单独表。(更少、更小的列会导致更快的检索。)通常我建议对 PK 使用 INT,因为它允许快速解析外键。

于 2013-04-03T16:14:36.197 回答