【问题标题】:SQL Server - Partitioned Tables vs. Clustered Index?SQL Server - 分区表与聚集索引?
【发布时间】:2008-09-23 12:39:53
【问题描述】:

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

[id] INT NOT NULL,

[date] SMALLDATETIME NOT NULL,

[sales] FLOAT NULL

还假设您仅限于一个物理磁盘和一个文件组 (PRIMARY)。您希望此表能够保存 10,000,000+ ids 的销售额,跨越 100 个日期(很容易 1B+ 记录)。

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

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

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

预期结果 #1: 这种设置对于数据加载来说会非常快,但在分析读取方面不是最理想的,因为在最坏的情况下(不受日期限制,不走运查询一组id),可以读取100%的数据页。

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

预期结果 #2: 加载数据时预期性能会受到巨大影响,因为我们无法再快速按日期限制。当涉及到我的分析查询时,预计会有巨大的性能优势,因为它将最小化读取的数据页数。

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

预期结果#3:不确定会发生什么。鉴于聚集索引中的第一列是 [id],因此(我的理解)数据是按 ID 排列的,我希望我的分析查询有良好的性能。但是,数据是按日期分区的,这与聚集索引的定义相反(但仍然对齐,因为日期是索引的一部分)。我还没有找到很多关于这种情况的文档,以及我可以从中获得哪些性能优势(如果有的话),这让我想到了最后一个额外的问题:

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

【问题讨论】:

    标签: sql sql-server database


    【解决方案1】:

    这张桌子非常窄。如果真正的表会这么窄,您应该很乐意进行表扫描而不是索引->查找。

    我会这样做:

    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 让您可以方便地访问特定的列... 集群视图 让您可以方便地访问特定的行。

    【讨论】:

    • 感谢您的回复。我不熟悉集群视图。当我用谷歌搜索它时,没有返回明确的结果。您能否提供/指出更多信息?
    • 当然,这里是 msdn msdn.microsoft.com/en-us/library/aa933148.aspx 最大的要求是模式绑定(当这个结构存在时,它会锁定对依赖结构的更改)。
    【解决方案2】:

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

    分区表的经验法则表明,分区的大小应约为 10m 行。

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

    您可能会在加载时发现聚集索引给您带来一些好处的情况,特别是如果您有在 ETL 过程中计算的派生计算(例如 Earned Premium)。在这种情况下,您可能会获得一些好处。如果您有一个您知道将一直执行的特定查询,那么为此使用聚集索引可能是有意义的。如果您期望这种类型的查询是应用程序完成的绝大多数工作,选项 #2 和 #3 只会使您受益匪浅。

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

    【讨论】:

      【解决方案3】:

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

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

      关于您最初的问题:我建议您选择 #1,其中包含 id 上的非聚集索引。

      【讨论】:

        【解决方案4】:

        我会做以下事情:

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

        【讨论】:

        • 你的最后一点很有趣。从浮点数转换为数值,您希望获得什么样的性能优势?
        • 您可以更精确地了解要存储的数据,数字数据类型是精确数字,而浮点数是近似数字。
        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          如果您的插入速度比 3.33 毫秒的日期时间分辨率更快,那么日期列上的聚集索引就不好。 如果这样做,您将获得 2 个具有相同值的键,并且您的索引必须获得另一个内部唯一性,这将增加其大小。

          我会选择你的第二个选项。

          【讨论】:

            猜你喜欢
            • 2018-05-08
            • 2010-11-23
            • 1970-01-01
            • 1970-01-01
            • 2013-08-20
            • 1970-01-01
            • 1970-01-01
            • 2015-06-14
            • 2011-03-24
            相关资源
            最近更新 更多