2009-10-21 46 views
7

这是在一个数据仓库索引性能BigInt有VS的VarChar

它有一个综合指数如下

ALTER TABLE [dbo].[Fact_Data] 
ADD CONSTRAINT [PK_Fact_Data] 
PRIMARY KEY CLUSTERED 
(
    [Column1_VarChar_10] ASC, 
    [Column2_VarChar_10] ASC, 
    [Column3_Int] ASC, 
    [Column4_Int] ASC, 
    [Column5_VarChar_10] ASC, 
    [Column6_VarChar_10] ASC, 
    [Column7_DateTime] ASC, 
    [Column8_DateTime] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, 
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON 
) ON [PRIMARY] 
GO 

在这种结构中,所有的VARCHAR 10列具有的事实表仅数值。在查询和索引方面,改变这个7800万行结构来保存BIGINT而不是VARCHAR对我来说会是有益的吗?

任何其他好处/缺点,我应该考虑什么?

回答

14

你应该肯定介绍一个代理INT IDENTITY()主键! INT已经为您提供了高达20亿行 - 是不是够了?

SQL Server上的这个主键/聚簇键的大小最多为64个字节(而不是4个,对于一个INT) - 这将使您的聚簇索引和所有非聚簇索引变得无法识别。整个集群密钥(所有8列)都将包含在该表的每个非聚集索引的每一页上 - 浪费大量空间。

所以在任何给定的索引表,你将有多达16倍以上的条目与替代INT集群的关键 - 这意味着大量减少I/O,大量少浪费时间阅读索引页。

试想建立与该表的外键关系....任何子表必须将主键的所有8列作为外键列,并在每个列中指定所有8列加入 - 多么噩梦!

即使只是将集群密钥更改为INT IDENTITY,每行最多可以节省60个字节 - 这可以达到4 GB的磁盘空间(以及服务器中的RAM使用量) 。这甚至没有开始计算非聚集索引的节省.......

当然,是的,我也会将VARCHAR(10)更改为INT或BIGINT - 如果它是一个数字,使字段类型的数字 - 没有任何意义,将它放在VARCHAR(10)上。但是,单凭这一点在速度或性能方面不会产生巨大影响 - 它只是使数据处理变得更加容易(例如,比较值等时不必总是转向数字类型)。

马克

+1

这是我的数据仓库中的一个事实表。没有使用PK作为FK的表格。 – 2009-10-21 21:28:41

+0

@Raj:啊,好吧,这解释了一些事情 - 你忘了提到这一点。但仍然:你在这张桌子上也有非聚集索引吗?那些肯定会有一个单一的INT或BIGINT主/集群密钥 – 2009-10-22 05:28:49

+0

bigint使用64位非字节,即它是两倍大,而不是16倍。 – Yrlec 2009-11-03 10:45:17

1

马克·S是正确的,该64字节的主键是怎么回事,所以你要支付的I/O成本,这将在数据量影响被复制到每一个NC索引保存在内存中(因为你在NC索引页面上浪费空间)。所以在这个基础上,问题不是'我应该转换我的varchars',而是'我应该考虑将我的聚簇索引转换为完全不同的东西。“/

根据varchar vs bigint,有一个很好的理由来转换if你可以负担得起的时间;即在每个字段的存储空间的2个字节差异之外,当您比较具有两种不同类型的值时,SQL将被迫转换其中的一个。这将发生在每一次比较中,无论是索引连接还是where子句中的谓词。

根据您选择数据的方式,将哪些维度表连接到事实数据表,您可能会在每个查询中为其加入转换费用成本,因为它必须将它。

4

有两件事情可以影响指数(和总体DB)性能:

1)索引页 2)比较速度

所以,对于第一个的大小,一般较小的索引/数据页面越多,您可以在内存中容纳的页面越多,并且给定查询可以在缓存中找到该页面的可能性与在慢速磁盘中找到页面的可能性越大。因此,您希望使用可以轻松满足现有和未来需求的最小数据类型。

BigInt是8个字节;如果数据的大小很小,VARCHAR可能会更小,所以它实际上取决于您的数据。但是,根据大小,10个字符长的数字可能适合SQL Server的INT数据类型(http://msdn.microsoft.com/en-us/library/ms187745.aspx),因此int和bigint取决于您的域。另外,如果整行的长度固定,SQL Server可以在扫描中进行某些优化,因为它确切知道下一行将在磁盘上的哪个位置(假定行是连续的)。可以肯定的是一个边缘案例,但它可以提供帮助。

对于第二个,比unicode字符串比整数更快。所以,如果您只存储数字数据,那么您绝对应该切换到适当大小的数字数据类型。

最后,马克是正确的,这成为一个非常复杂的主键。然而,如果你的数据保证了它 - 例如这些只是你的专栏,而且你从来不会做添加查询 - 你可能会非常好地将优化版本(使用Bigints等)作为主键。不过,有种代码味道,所以我会回应他的建议,真正看看你的数据模型,看看这是否正确。