【问题标题】:Sql Server Primary Key With Partition Issue具有分区问题的 Sql Server 主键
【发布时间】:2011-10-04 23:02:15
【问题描述】:

我正在构建一个将被分区并包含FILESTREAM 列的表。我遇到的问题是我必须有一个复合主键(FILE_IDFILE_UPLOADED_DATE),因为FILE_UPLOADED_DATE 是我的分区方案的一部分。那是对的吗?我不希望这是一个复合键,而只是将 FILE_ID 作为主键.....这可能只是一个用户错误吗?

任何建议将不胜感激。

版本:SQL Server 2008 R2

分区方案和功能:

CREATE PARTITION FUNCTION DocPartFunction (datetime)
AS RANGE RIGHT FOR VALUES ('20101220')
GO
CREATE PARTITION SCHEME DocPartScheme AS
PARTITION DocPartFunction TO (DATA_FG_20091231, DATA_FG_20101231);
GO
CREATE PARTITION SCHEME DocFSPartScheme AS
PARTITION DocPartFunction TO (FS_FG_20091231,FS_FG_20101231);
GO

创建语句:

CREATE TABLE [dbo].[FILE](
    [FILE_ID] [int] IDENTITY(1,1) NOT NULL,
    [DOCUMENT] [varbinary](max) FILESTREAM  NULL,
    [FILE_UPLOADED_DATE] [datetime] NOT NULL,
    [FILE_INT] [int] NOT NULL,
    [FILE_EXTENSION] [varchar](10) NULL,
    [DocGUID] [uniqueidentifier] ROWGUIDCOL  NOT NULL UNIQUE ON [PRIMARY],
CONSTRAINT [PK_File] PRIMARY KEY CLUSTERED
    (   [FILE_ID] ASC
    ) ON DocPartScheme ([FILE_UPLOADED_DATE])
)ON DocPartScheme ([FILE_UPLOADED_DATE])
FILESTREAM_ON DocFSPartScheme;

如果我不包含FILE_UPLOADED_DATE,则会出错:

Msg 1908, Level 16, State 1, Line 1
Column 'FILE_UPLOADED_DATE' is partitioning column of the index 'PK_File'. Partition columns for a unique index must be a subset of the index key.
Msg 1750, Level 16, State 0, Line 1
Could not create constraint. See previous errors.

谢谢!

【问题讨论】:

    标签: sql-server sql-server-2008 filestream


    【解决方案1】:

    您混淆了主键和聚集索引。两者没有理由是一回事。您可以在FILE_UPLOADED_DATE 上拥有一个聚集索引,在FILE_ID 上拥有一个单独的非聚集主键。事实上,您已经为 DocGUID 列做了类似的事情:

    CREATE TABLE [dbo].[FILE](
        [FILE_ID] [int] IDENTITY(1,1) NOT NULL,
        [DOCUMENT] [varbinary](max) FILESTREAM  NULL,
        [FILE_UPLOADED_DATE] [datetime] NOT NULL,
        [FILE_INT] [int] NOT NULL,
        [FILE_EXTENSION] [varchar](10) NULL,
        [DocGUID] [uniqueidentifier] ROWGUIDCOL  NOT NULL,
        constraint UniqueDocGUID UNIQUE NONCLUSTERED ([DocGUID]) 
            ON [PRIMARY])
        ON DocPartScheme ([FILE_UPLOADED_DATE])
        FILESTREAM_ON DocFSPartScheme;
    
    CREATE CLUSTERED INDEX cdx_File 
       ON [FILE] (FILE_UPLOADED_DATE)
       ON DocPartScheme ([FILE_UPLOADED_DATE])
       FILESTREAM_ON DocFSPartScheme;
    
    ALTER TABLE [dbo].[FILE]
        ADD CONSTRAINT PK_File PRIMARY KEY NONCLUSTERED (FILE_ID)
        ON [PRIMARY];
    

    但是这样的设计会导致索引不对齐,这会导致非常严重的性能问题,并且还会阻塞所有快速的分区切换操作。见Special Guidelines for Partitioned Indexes

    每个排序表都需要最少的内存来构建。当你 正在构建与其基表对齐的分区索引, 排序表一次构建一个,使用更少的内存。然而,当 您正在构建非对齐分区索引,排序表是 同时建造。

    因此,必须有足够的内存来处理这些 并发排序。分区数越大,内存越多 必需的。对于每个分区,每个排序表的最小大小是 40 页,每页 8 KB。例如,一个不对齐的 具有 100 个分区的分区索引需要足够的内存 同时对 4,000 (40 * 100) 页进行连续排序。如果这段记忆 可用,构建操作将成功,但性能可能 遭受。如果此内存不可用,则构建操作将失败

    您的设计已经有 DocGUID 的非对齐索引,因此可能已经存在性能问题。如果您必须保持索引对齐,那么您必须承认选择分区方案的副作用之一:您不能再拥有逻辑主键,也不能强制执行唯一约束,除非该键包含分区键。

    最后,有人必须问:为什么要使用分区表?它们总是比未分区的替代方案慢。除非您需要对 ETL 进行快速分区切换操作(由于 DocGUID 上的非对齐索引,您已经在使用它),否则基本上没有使用分区表的动机。 (抢先评论:FILE_UPLOADED_DATE 上的聚集索引保证比“分区消除”更好)。

    【讨论】:

    • 莱姆斯,非常感谢您提供的信息。我需要分区,这样我就可以将文件流文件组带到另一个位置......但只有最新的,因为我们有空间限制......长篇大论。
    • 您提供的上述解决方案不起作用?部分原因是保留字“FILE_ID”,但在修复后,当我尝试使用上述结构构建表时,它仍然会引发错误。
    • 我已经修复了我的脚本(这次测试了它)。使用分区进行文件组管理是部署分区的正当理由。不幸的是,对 ROWGUIDCOL 上的唯一约束的 FILESTREAM 要求是保证未对齐索引,这可能会导致将来出现问题(例如,如果您需要使用快速分区切换来删除已延长最大强制保留策略生命周期的文档)。
    • 谢谢莱姆斯!非常感谢您的帮助。
    【解决方案2】:

    分区列必须始终存在于分区表的聚集索引中。您想出的任何解决方法都必须考虑到这一点。

    【讨论】:

      【解决方案3】:

      我知道,这是一个老问题,但也许 google 会引导其他人回答这个问题:

      一个可能的解决方案是不按日期列分区,而是按 File_ID 分区。每天/每周/每月(或您使用的任何时间段)您必须在午夜运行代理作业,该作业采用Max(File_ID) 其中file_uploadet_date < GetDate(),将下一个文件组添加到分区方案并在@987654323 上进行拆分@。

      当然,您仍然会遇到 DocID 上未对齐索引的问题,除非您也将 file_id 添加到此唯一索引(可能导致非唯一 DocId)和/或在插入中检查其唯一性/更新触发器。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-30
        • 1970-01-01
        • 2016-09-27
        相关资源
        最近更新 更多