我正在构建一个表,它将被分区并包含一个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.
谢谢!
您混淆了主键和聚集索引。这两者没有理由是同一的。可以在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];
然而,这样的设计将导致索引不对齐,这会导致非常严重的性能问题,并且还会阻塞所有快速分区切换操作。参见分区索引的特殊指南:
每个排序表需要最少的内存来构建。当你正在构建一个与其基表对齐的分区索引,排序表一次构建一个,使用更少的内存。然而,当您正在构建一个非对齐的分区索引,排序表是同时建造。
因此,必须有足够的内存来处理这些并发。分区数量越大,内存就越多必需的。对于每个分区,每个排序表的最小大小是40页,每页8千字节。例如,不结盟具有100个分区的分区索引需要足够的内存同时连续排序4000个(40 * 100)页。如果这段记忆可用时,构建操作将成功,但性能可能会成功受到影响。如果此内存不可用,则构建操作将失败
您的设计已经为DocGUID提供了一个非对齐索引,因此性能问题可能已经存在。如果你必须保持你的索引对齐你不得不承认的副作用之一选择一个分区方案:你可以不再有逻辑主键,也不是唯一的约束执行,除非包括分区键的关键。
最后,人们必须问:为什么要使用分区表?它们总是比非分区的备选方案慢。除非您需要对ETL进行快速分区切换操作(由于DocGUID上的索引未对齐,您已经在进行切换),否则基本上没有理由使用分区表。(先发制人的评论:在FILE_UPLOADED_DATE上的聚集索引保证是比"分区消除"更好的选择)。
分区列必须始终存在于分区表的聚集索引中。你想出的任何解决方法都必须考虑到这一点。
我知道,这是一个古老的问题,但也许谷歌会引导别人问这个问题:
一个可能的解决方案是不按日期列分区,而是按File_ID分区。每天/每周/每月(或您使用的任何时间段)都必须在午夜运行代理作业,该作业将Max(File_ID)
(file_uploadet_date < GetDate()
)添加到分区方案中,并在MaxID + 1
上进行拆分。
当然,您仍然会遇到在DocID上未对齐索引的问题,除非您将file_id
也添加到这个唯一索引(可能导致非唯一的DocID)和/或在插入/更新触发器中检查其唯一性