SQL Server - 分区表与聚簇索引?

时间:2008-09-23 12:39:53

标签: sql sql-server database

假设您有一个包含三列的大型表,如下所示:

[id] INT NOT NULL,

[date] SMALLDATETIME NOT NULL,

[sales] FLOAT NULL

还假设您仅限于一个物理磁盘和一个文件组(PRIMARY)。您希望此表能够在100个日期(10,000个以上的记录)中保持10,000,000+ ID的销售额。

与许多数据仓库方案一样,数据通常按日期顺序增长(即,每次执行数据加载时,您将插入新日期,并可能更新一些最近的数据日期)。出于分析目的,通常会查询和聚合数据,以便随机设置~10,000个ID,这些ID将通过与另一个表的连接来指定。通常,这些查询不指定日期范围,或指定非常宽的日期范围,这引出了我的问题:索引/分区此表的最佳方法是什么?

我已经考虑了一段时间了,但我遇到了相互矛盾的解决方案:

选项#1:由于数据将按日期顺序加载,请将聚集索引(和主键)定义为[date],[id]。还可以在日期创建“滑动窗口”分区功能/方案,允许新数据快速移入/移出表格。可以在id上创建非聚集索引以帮助查询。

预期结果#1:此设置对于数据加载非常快,但在分析读取方面是次优的,在最坏的情况下(不受日期限制,不吉利)使用id的查询集,可以读取100%的数据页。

选项#2:由于一次只查询一小部分ID的数据,请将聚集索引(和主键)定义为[id],[date]。不要费心去创建分区表。

预期成果#2 :在加载数据时,预计会出现巨大的性能损失,因为我们无法再按照日期快速限制。对于我的分析查询,预计会带来巨大的性能优势,因为它可以最大限度地减少读取的数据页数。

选项#3:群集(和主键)如下:[id],[date]; “滑动窗口”分区功能/方案日期。

预期结果#3:不确定会发生什么。鉴于聚集索引中的第一列是[id],因此(这是我的理解)数据按ID排列,我希望我的分析查询具有良好的性能。但是,数据按日期划分,这与聚簇索引的定义相反(但仍然对齐为日期是索引的一部分)。我没有找到很多能够说明这种情况的文档,以及我可以从中获得的性能优势,这会带给我最终的奖励问题:

如果我在一个磁盘上的一个文件组上创建一个表,并且在一列上有聚簇索引,那么在同一列上定义一个分区时,是否有任何好处(除了加载数据时的分区切换)? p>

6 个答案:

答案 0 :(得分:7)

这张桌子非常窄。如果真实表格的范围很窄,您应该乐于进行表扫描而不是索引 - >查找。

我会这样做:

CREATE TABLE Narrow
(
  [id] INT NOT NULL,
  [date] SMALLDATETIME NOT NULL,
  [sales] FLOAT NULL,
  PRIMARY KEY(id, date)  --EDIT, just noticed your id is not unique.
)

CREATE INDEX CoveringNarrow ON Narrow(date, id, sales)

使用针对日期条件和id标准的有限扫描来查找具有搜索和宽范围查询的点查询。索引中没有每条记录的查找。是的,我把写入时间(和使用的空间)增加了一倍,但这很好,imo。


如果需要某个特定的数据(并且需要通过分析来证明 !!),我会创建一个聚集视图来定位该表的那一部分。

CREATE VIEW Narrow200801
AS
SELECT * FROM Narrow WHERE '2008-01-01' <= [date] AND [date] < '2008-02-01'
--There is some command that I don't have at my finger tips to make this a clustered view.

可以按名称在查询中使用聚簇视图,或者当FROM和WHERE子句合适时,优化器将选择使用聚簇视图。例如,此查询将使用群集视图。请注意,查询中引用了基表。

SELECT SUM(sales) FROM Narrow WHERE '2008-01-01' <= [date] AND [date] < '2008-02-01'

由于 index 可让您方便地访问特定列... Clustered view 可让您方便地访问特定行。

答案 1 :(得分:3)

聚合索引将在本地化I / O时为查询提供性能优势。日期是传统的分区策略,因为许多D / W查询按日期查看移动。

分区表的经验法则表明分区的大小应该在10米左右。

在不同的分析工作负载上,聚集索引可以获得很多性能提升,这有点不寻常。查询优化器将使用名为'Index Intersection'的技术来选择行,甚至不会访问事实表。有关我在另一个问题上所做的帖子,请参阅Here,该问题可以通过一些链接进行更深入的解释。 聚簇索引可能会也可能不会参与索引交集,因此您可能会发现它在一般查询工作负载上获得的收益相对较少。

您可能会在加载中发现聚集索引为您带来一些好处的情况,特别是如果您在ETL过程中计算了派生计算(例如Earned Premium)。在这种情况下,您可能会获得一些好处。如果您有一个特定的查询,您知道它将一直执行,为此使用聚簇索引可能是有意义的。如果您希望此类查询成为应用程序完成的绝大部分工作,则选项#2和#3将对您有显着的好处。

对于一个灵活的系统,一个简单的日期范围分区,在ID上有一个索引(如果分区保持一个范围,那么日期可能会让你获得与任何一个一样好的性能。你可能会从索引限制情况的集群中获得一些好处您可能还会通过在数据上构建多维数据集并确保为此查询正确设置聚合来获得一些里程。

答案 2 :(得分:0)

如果您在select语句中使用分区,那么您可以获得一些速度。

如果您不使用它,只使用“标准”选择,那么您没有任何好处。

关于你原来的问题:我建议你选择#1,其中包含id的非聚集索引。

答案 3 :(得分:0)

我会做以下事情:

  • [Id]
  • 上的非聚集索引
  • [日期]上的聚集索引
  • 将[sales]数据类型转换为numeric而不是float

答案 4 :(得分:0)

按日期对表进行分区。几个水平分区比具有那么多行的一个大表更具性能。

答案 5 :(得分:0)

如果插入的插入速度比3.33 ms的日期时间分辨率更快,则日期列上的聚簇索引不好。 如果你这样做,你将获得具有相同值的2个密钥,并且你的索引必须得到另一个内部uniquifier,这将增加它的大小。

我选择你的选择#2。