索引性能BigInt vs VarChar

时间:2009-10-21 20:40:03

标签: sql-server-2005 tsql performance

这是数据仓库中的 FACT表

它有一个复合索引如下

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会对我有益吗?

我应该考虑的任何其他好处/缺点?

3 个答案:

答案 0 :(得分:14)

你应该明确引入代理INT IDENTITY()主键!! INT已经为您提供了多达20亿行 - 这还不够吗?

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

因此,在任何给定的索引表中,使用代理INT聚簇键的条目最多可达16倍 - 这意味着I / O减少了很多,浪费了很多时间来读取索引页。

想象一下,尝试与该表建立外键关系......任何子表都必须将主键的所有 8列作为外键列,并指定所有每次加入都有8列 - 真是个噩梦!

在7800万行中,即使只将集群密钥更改为INT IDENTITY,每行最多可节省60个字节 - 仅此一项就可以达到4 GB的磁盘空间(以及服务器中的RAM使用率)。而这甚至没有开始计算非聚集指数的节省.......

当然,是的,我也会将VARCHAR(10)更改为INT或BIGINT - 如果它是一个数字,请将字段类型设为数字 - 确保将其保留在VARCHAR(10)没有意义。但仅凭这一点并不会在速度或性能方面产生巨大的差异 - 它只是使得处理数据变得更加容易(例如,在比较值等时不必总是转换为数字类型)。 / p>

马克

答案 1 :(得分:4)

可能影响索引(和整体数据库)性能的两件事:

1)索引页面的大小 2)比较速度

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

BigInt是8个字节;如果数据的大小很小,VARCHAR可以更小,因此它实际上取决于您的数据。但是,10个字符的长数字可能适合SQL Server的INT数据类型(http://msdn.microsoft.com/en-us/library/ms187745.aspx),具体取决于大小,因此int与bigint取决于您的域。

此外,如果您的整行具有固定长度,则SQL Server可以在扫描中执行某些优化,因为它确切地知道下一行将在磁盘上的哪个位置(假设行是连续的)。一个边缘的情况,当然,但它可以帮助。

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

最后,Marc是正确的,这成为一个非常复杂的主键。但是,如果您的数据需要保证 - 例如这些是您的唯一列,并且您从未进行过add'l查询 - 您可能完全可以将优化版本(使用Bigints等)作为主键。但是,有一种代码味道,所以我会回应他的建议,真正看看你的数据模型,看看这是否正确。

答案 2 :(得分:1)

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

就varchar和bigint而言,如果你能负担得起时间,就有充分的理由进行转换;这超出了每个字段的2字节存储差异,当您比较两种不同类型的值时,SQL将被强制转换其中一种。每次比较都会发生这种情况,无论是索引连接还是where子句中的谓词。

根据您选择数据的位置,哪些维度表连接到事实表,您可能会在每个查询上获取转换开销成本,以便加入,因为它必须转换它的一面