#sql-server #sql-server-2008 #filestream
#sql-server #sql-server-2008 #filestream
Вопрос:
Я создаю таблицу, которая будет разделена на разделы и содержать 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:
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.
Спасибо!
Ответ №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];
Однако такая конструкция приведет к несогласованным индексам, что может вызвать очень серьезные проблемы с производительностью, а также заблокировать все операции быстрого переключения разделов. См. Специальные рекомендации для секционированных индексов:
Для построения каждой таблицы сортировки требуется минимальный объем памяти. Когда вы создаете секционированный индекс, который выровнен с его базовой таблицей, таблицы сортировки создаются по одной за раз, используя меньше памяти. Однако, когда вы создаете невыровненный секционированный индекс, таблицы сортировки создаются одновременно.
В результате должно быть достаточно памяти для обработки этих параллельных сортировок. Чем больше количество разделов, тем больше памяти требуется. Минимальный размер каждой таблицы сортировки для каждого раздела составляет 40 страниц, по 8 килобайт на страницу. Например, для невыровненного секционированного индекса со 100 разделами требуется достаточно памяти для одновременной последовательной сортировки 4000 (40 * 100) страниц. Если эта память доступна, операция сборки завершится успешно, но производительность может пострадать. Если эта память недоступна, операция сборки завершится с ошибкой
В вашем проекте уже есть не выровненный индекс для DocGUID, поэтому проблемы с производительностью, вероятно, уже присутствуют. Если вы должны выровнять свои индексы, то вы должны признать один из побочных эффектов выбора схемы разделения: у вас больше не может быть логического первичного ключа или принудительного применения уникальных ограничений, если ключ не включает ключ разделения.
И, наконец, нужно спросить: зачем использовать секционированную таблицу? Они всегда работают медленнее, чем альтернатива без разделов. Если вам не нужны быстрые операции переключения разделов для ETL (которые вы уже используете из-за несогласованного индекса в DocGUID), в принципе, нет никакого стимула использовать секционированную таблицу. (Упреждающий комментарий: кластеризованный индекс в FILE_UPLOADED_DATE гарантированно является лучшей альтернативой, чем «удаление раздела»).
Комментарии:
1. Ремус, большое тебе спасибо за информацию. Мне нужен раздел, чтобы я мог перенести файловую группу filestream в другое место ….. но только самые новые, потому что у нас есть ограничения по пространству…. Долгая история.
2. указанное выше решение, которое вы предоставили, не работает? Частично это было из-за зарезервированного слова «FILE_ID», но после исправления оно по-прежнему выдает ошибки, когда я пытаюсь построить таблицу с вышеуказанной структурой.
3. Я исправил свой скрипт (протестировал его на этот раз). Использование секционирования для управления файловыми группами является веской причиной для развертывания секционирования. К сожалению, требование FILESTREAM для ограничения уникальности в ROWGUIDCOL является гарантированным невыровненным индексом, и это может вызвать проблемы в будущем (например. если вам когда-нибудь понадобится использовать fast partition switch для удаления документов, которые продлили максимальный срок действия политики обязательного хранения).
Ответ №2:
Столбец секционирования всегда должен присутствовать в кластеризованном индексе секционированной таблицы. Любое решение, которое вы предлагаете, должно учитывать это.
Ответ №3:
Я знаю, это старый вопрос, но, возможно, Google приводит кого-то еще к этому вопросу:
Возможным решением было бы разделение не по столбцу даты, а по File_ID. Каждый день / неделю / месяц (или любой другой период времени, который вы используете) вы должны запускать задание агента в полночь, которое принимает Max(File_ID)
where file_uploadet_date < GetDate()
, добавляет следующую файловую группу в схему разделов и выполняет разделение на MaxID 1
.
Конечно, у вас все равно будет проблема с не выровненным индексом в идентификаторе DocID, за исключением того, что вы также добавляете file_id
к этому уникальному индексу (может привести к неуникальным идентификаторам DOCID) и / или проверяете его уникальность в триггере вставки / обновления.