Sql Server первичный ключ с проблемой раздела - PullRequest
5 голосов
/ 05 октября 2011

Я строю таблицу, которая будет разбита на разделы и будет содержать столбец 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.

Спасибо!

Ответы [ 3 ]

10 голосов
/ 05 октября 2011

Вы путаете первичный ключ и кластерный индекс. Нет причин для того, чтобы они были одним и тем же. Вы можете иметь кластеризованный индекс на 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 гарантированно является лучшей альтернативой, чем «исключение раздела»).

4 голосов
/ 05 октября 2011

Столбец секционирования всегда должен присутствовать в кластеризованном индексе секционированной таблицы.Любой обходной путь, который вы придумаете, должен учитывать это.

0 голосов
/ 24 марта 2015

Я знаю, это старый вопрос, но, возможно, Google приводит кого-то еще к этому вопросу:

Возможным решением будет не разделение по столбцу даты, а по File_ID.Каждый день / неделю / месяц (или любой другой период времени, который вы используете) вы должны запускать задание агента в полночь, которое принимает Max(File_ID), где file_uploadet_date < GetDate(), добавляет следующую файловую группу в схему секционирования и выполняет разбиение на * 1005.*.

Конечно, у вас все еще будет проблема с невыровненным индексом на DocID, за исключением того, что вы добавите file_id к этому уникальному индексу тоже (может вызвать неуникальные DocIds) и / или проверьте егоуникальность в триггере вставки / обновления.

...