我正在构建一个将被分区并包含FILESTREAM
列的表。我遇到的问题是,似乎我必须有一个复合主键(FILE_ID
和FILE_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.
谢谢!
答案 0 :(得分:10)
您将主键和聚簇索引混淆。这两者没有理由是同一个。您可以在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千字节。例如,一个不对齐的 具有100个分区的分区索引需要足够的内存 同时对4,000(40 * 100)页进行连续排序。如果这个记忆 可用,构建操作将成功,但性能可能会 遭受。如果此内存不可用,则构建操作将失败
您的设计已经有一个DocGUID的非对齐索引,因此性能问题可能已经存在。如果必须保持索引一致,则必须承认选择分区方案的一个副作用:除非密钥包含分区键,否则不能再使用逻辑主键,也不能使用唯一约束强制执行。
最后,必须要问:为什么要使用分区表?它们始终比未分区的替代品慢。除非您需要ETL的快速分区切换操作(由于DocGUID上的非对齐索引,您已经开始使用),因此基本上没有动机使用分区表。 (抢先评论:FILE_UPLOADED_DATE上的聚集索引保证比'分区消除'更好的选择。)
答案 1 :(得分:4)
分区列必须始终存在于分区表的聚簇索引中。你提出的任何解决办法都必须考虑到这一点。
答案 2 :(得分:0)
我知道,这是一个古老的问题,但也许谷歌会引导别人来讨论这个问题:
一种可能的解决方案是不按日期列进行分区,而是按File_ID进行分区。每天/每周/每月(或您使用的任何时间段)您必须在午夜运行代理作业,Max(File_ID)
file_uploadet_date < GetDate()
,将下一个文件组添加到分区方案并进行拆分在MaxID + 1
。
当然,您仍然会遇到DocID上非对齐索引的问题,除非您将file_id
添加到此唯一索引(可能导致非唯一DocIds)和/或检查其唯一性插入/更新触发器。