各种数据类型的SQL设计

时间:2009-08-12 09:26:30

标签: sql-server performance database-design types

我需要使用不同数据类型的各种数据源将数据存储在SQL Server 2008数据库中。允许的数据类型有:位,数字(1,2或4字节),Real和String。对于值所属的项目将存在值,时间戳,FK以及存储的数据的一些其他信息。

最重要的一点是数据的读取性能大小。可能有几千个项目,每个项目可能有数百万个值。

我有5种可能的选择:

  1. 每种数据类型的单独表格(ValueBit,ValueTinyInt,ValueSmallInt等...表格)
  2. 使用继承分隔表(Value表作为基表,ValueBit表仅用于存储Bit值等)
  3. 所有数据类型的单值表,每种数据类型都有单独的字段(值表,使用ValueBit BIT,ValueTinyInt TINYINT等...)
  4. 使用sql_variant
  5. 的单个表和单值字段
  6. 使用UDT的单表和单值字段
  7. 对于案例2,必须使用PK,

    1000 item * 10 000 000 data each > Int32.Max, and,
    1000 item * 10 000 000 data each * 8 byte BigInt PK is huge
    

    除此之外,我正在考虑没有PK的1或3。它们的大小会有所不同吗?

    我没有4或5的经验,我认为他们在这种情况下表现不佳。

    我该走哪条路?

3 个答案:

答案 0 :(得分:1)

您的问题很难回答,因为您似乎使用关系数据库系统来处理不适合的事情。您希望保留在数据库中的数据似乎太过非结构化,无法从关系数据库系统中获得太多好处。主要用于覆盖非常一般情况的“参数类型”和“参数值”等字段的数据库设计大多被认为是糟糕的设计。也许您应该考虑使用像BigTable这样的“非关系型数据库”。如果您真的想使用关系数据库系统,我强烈建议您阅读Clare Churcher的 Beginning Database Design 。这是一个简单的阅读,但让你在RDBS方面走上正确的轨道。

答案 1 :(得分:0)

我认为这是一个很好的问题 - 这种情况相当普遍,但制作表格以支持它是很尴尬的。

就性能而言,拥有#3中指示的表可能会浪费大量的存储空间和RAM,因为每行都为每种类型的值分配空间,但只使用一个。如果您使用2008的新稀疏表功能,它可能会有所帮助,但也存在其他问题:它有点难以约束/规范化,因为您只希望为每行填充多个值中的一个 - 具有两个值在两列中将是一个错误,但设计并未反映出这一点。我会把它交叉掉。

所以,如果是我,我会查看选项1或2或4,并且决定将由此驱动:我通常需要进行一次查询,返回具有 mix的行同一结果集中不同类型的值?或者我几乎总是会按类型按项请求行。我问,因为如果值是不同的类型,它意味着我在源或使用该数据方面存在一些差异(例如,您不太可能比较字符串和实数,或字符串和位。)这是相关的,因为每种类型具有不同的表实际上可能是一个重要的性能/可伸缩性优势,如果以这种方式对数据进行分区会使查询更快。将数据划分为更小的更密切相关的数据集可以提供性能优势。

这就像将所有数据放在一个庞大的(尽管是有序的)集合中,或者将它分成较小的相关集合。较小的集合支持某些类型的查询,如果这些是你需要的查询,那就是胜利。

详细说明:

CREATE TABLE [dbo].[items](
    [itemid] [int] IDENTITY(1,1) NOT NULL,
    [item] [varchar](100) NOT NULL,
 CONSTRAINT [PK_items] PRIMARY KEY CLUSTERED 
(
    [itemid] ASC
)
) 

/* This table has the problem of allowing two values 
in the same row, plus allocates but does not use a 
lot of space in memory and on disk (bad): */

CREATE TABLE [dbo].[vals](
    [itemid] [int] NOT NULL,
    [datestamp] [datetime] NOT NULL,
    [valueBit] [bit] NULL,
    [valueNumericA] [numeric](2, 0) NULL,
    [valueNumericB] [numeric](8, 2) NULL,
    [valueReal] [real] NULL,
    [valueString] [varchar](100) NULL,
 CONSTRAINT [PK_vals] PRIMARY KEY CLUSTERED 
(
    [itemid] ASC,
    [datestamp] ASC
)
) 

ALTER TABLE [dbo].[vals]  WITH CHECK 
ADD  CONSTRAINT [FK_vals_items] FOREIGN KEY([itemid])
REFERENCES [dbo].[items] ([itemid])
GO

ALTER TABLE [dbo].[vals] CHECK CONSTRAINT [FK_vals_items]
GO


/* This is probably better, though casting is required 
all the time. If you search with the variant as criteria, 
that could get dicey as you have to be careful with types, 
casting and indexing. Also everything is "mixed" in one 
giant set */

CREATE TABLE [dbo].[allvals](
    [itemid] [int] NOT NULL,
    [datestamp] [datetime] NOT NULL,
    [value] [sql_variant] NOT NULL
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[allvals]  WITH CHECK 
ADD  CONSTRAINT [FK_allvals_items] FOREIGN KEY([itemid])
REFERENCES [dbo].[items] ([itemid])
GO

ALTER TABLE [dbo].[allvals] CHECK CONSTRAINT [FK_allvals_items]
GO


/* This would be an alternative, but you trade multiple 
queries and joins for the casting issue. OTOH the implied
partitioning might be an advantage */

CREATE TABLE [dbo].[valsBits](
    [itemid] [int] NOT NULL,
    [datestamp] [datetime] NOT NULL,
    [val] [bit] NOT NULL
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[valsBits]  WITH CHECK 
ADD  CONSTRAINT [FK_valsBits_items] FOREIGN KEY([itemid])
REFERENCES [dbo].[items] ([itemid])
GO

ALTER TABLE [dbo].[valsBits] CHECK CONSTRAINT [FK_valsBits_items]
GO

CREATE TABLE [dbo].[valsNumericA](
    [itemid] [int] NOT NULL,
    [datestamp] [datetime] NOT NULL,
    [val] numeric( 2, 0 ) NOT NULL
) ON [PRIMARY]

GO

... FK constraint ...

CREATE TABLE [dbo].[valsNumericB](
    [itemid] [int] NOT NULL,
    [datestamp] [datetime] NOT NULL,
    [val] numeric ( 8, 2 ) NOT NULL
) ON [PRIMARY]

GO

... FK constraint ...

etc...

答案 2 :(得分:0)

什么是使用场景?从查询示例开始并计算必要的索引。 考虑前面提到的数据分区。尝试更多地了解您的数据/关系。我认为决定应该基于数据的商业含义/用法。