Как разбить существующую однораздельную таблицу

22

У меня есть существующая таблица с данными:

dbo.Test (col1,col2,col3....) ON [PRIMARY]

Мне нужно изменить эту таблицу так, чтобы она была разделена следующим образом:

dbo.Test(col1,col2,col3....) ON Ps_Date(Col2)

Как я могу добиться этого, не опуская и не воссоздавая стол?

343
источник

Ответы:

23

Чтобы разделить таблицу, вы можете выполнить следующие короткие шаги:

  • сначала создайте функцию разделения и схему разбиения
  • После этого вы можете разделить таблицу.
  • Если ваша таблица имеет кластеризованный индекс, то вам нужно удалить и DROP_EXISTINGзаново создать его в нужном разделе, или вы можете использовать предложение для повторного создания кластеризованного индекса.
  • Если ваша таблица не имеет кластеризованного индекса, вы можете просто создать его в правом разделе, используя схему разделов.
  • Кроме того, Enterprise Edition имеет возможность использовать ONLINE=ONопцию оператора CREATE INDEX, чтобы минимизировать время простоя для вашего приложения. Обратите внимание, что вы увидите снижение производительности во время перестроения индекса с использованием опции ONLINE.

Чтобы автоматизировать разбиение, вы можете использовать утилиту управления разделами SQL Server или платформу многораздельных таблиц SQL Server, также доступную в codeplex.

Некоторые хорошие ресурсы:

Кин Шах
источник
53

Вы не указываете, имеет ли ваша таблица кластеризованный индекс или нет, поэтому давайте рассмотрим все варианты.

Я собираюсь использовать этот пример функции секционирования, схемы секционирования и таблицы:

CREATE PARTITION FUNCTION pf1(INT) AS RANGE LEFT FOR VALUES(10,20,30,40);
GO
CREATE PARTITION SCHEME ps1 AS PARTITION pf1 ALL TO ([PRIMARY])
GO
CREATE TABLE dbo.pt(pc INT NOT NULL, id INT NOT NULL) ON [PRIMARY];
GO

1. Ваша таблица имеет кластерный индекс, который не был создан по ограничению.

Это самый простой случай. Вы можете просто использовать CREATE INDEXоператор с DROP_EXISTINGпредложением, чтобы переместить таблицу в схему секционирования.

Предположим для примера, что этот кластерный индекс был создан:

CREATE UNIQUE CLUSTERED INDEX ptc ON dbo.pt(Id) ON [PRIMARY];

Чтобы разделить эту таблицу, кластеризованный индекс должен включать столбец раздела (в нашем случае pt) как часть ключа. Этот оператор изменяет кластеризованный индекс, чтобы включить столбец раздела и разделить его одновременно:

CREATE UNIQUE CLUSTERED INDEX ptc ON dbo.pt(pc, Id) WITH(DROP_EXISTING = ON)ON ps1(pc) ;

Предложение DROP_Existingавтоматически удаляет существующий индекс перед созданием нового. Это предпочтительнее отдельного, DROP INDEXпоскольку некластеризованные индексы перестраиваются только один раз.

2. Ваша таблица имеет кластерный индекс, который является частью ограничения PRIMARY KEYили, UNIQUEи содержит столбец раздела как часть ключа.

Этот по-прежнему прост и очень похож на предыдущий.

Предположим, что это PRIMARY KEYограничение было создано в таблице:

ALTER TABLE dbo.pt ADD CONSTRAINT ptc PRIMARY KEY CLUSTERED (pc, Id) ON [PRIMARY];

Теперь вы можете просто запустить тот же скрипт повторного создания, который мы использовали в 1:

CREATE UNIQUE CLUSTERED INDEX ptc ON dbo.pt(pc, Id) WITH(DROP_EXISTING = ON)ON ps1(pc) ;

3. Таблица имеет кластеризованный индекс, который не включает столбец раздела, но был создан как часть ограничения PRIMARY KEYилиUNIQUE

Везет, как утопленнику. Вы не можете изменить определение PRIMARY KEYили UNIQUEограничения после факта. Единственный вариант - удалить ограничение, а затем либо заново создать его, включая столбец раздела, либо создать кластеризованный индекс, независимый от ограничения, включающего столбец раздела. Во втором случае вы можете заново создать ограничение, NONCLUSTEREDне включая столбец раздела. Поскольку теперь это ограничение не выровнено (то есть его поддерживающий индекс не разбит на разделы), вы должны указать, где разместить его на диске.

Предположим, что таблица имеет первичный ключ, как это:

ALTER TABLE dbo.pt ADD CONSTRAINT ptc PRIMARY KEY CLUSTERED (Id) ON [PRIMARY];

Чтобы разделить эту таблицу, вы должны сначала удалить ограничение:

ALTER TABLE dbo.pt DROP CONSTRAINT ptc;

Затем вам нужно создать секционированный кластерный индекс:

CREATE UNIQUE CLUSTERED INDEX ptci ON dbo.pt(pc, Id) ON ps1(pc) ;

Если вы решите заново создать PRIMARY KEYневыровненное ограничение, вы можете сделать это следующим образом:

ALTER TABLE dbo.pt ADD CONSTRAINT ptc PRIMARY KEY NONCLUSTERED (Id) ON [PRIMARY];

4. Ваша таблица не имеет кластеризованного индекса

В этом случае рекомендуется в большинстве случаев просто создать кластеризованный индекс для установления разделения. Для этого вы можете использовать ранее созданный оператор создания индекса:

CREATE UNIQUE CLUSTERED INDEX ptci ON dbo.pt(pc, Id) ON ps1(pc) ;

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

Предположим, что ваша таблица не имеет кластеризованного индекса. Чтобы разделить таблицу, вам нужно сначала создать CLUSTERED UNIQUEограничение. (Вы также можете использовать CLUSTERED PRIMARY KEYограничение). Если у вас есть уникальная комбинация столбцов, это простой шаг:

ALTER TABLE dbo.pt ADD CONSTRAINT ptc UNIQUE CLUSTERED(pc,id);

После того, как ограничение создано, вы можете снова его удалить и одновременно «переместить» таблицу на новую схему секционирования:

ALTER TABLE dbo.pt DROP CONSTRAINT ptc WITH(MOVE TO ps1(pc));

Если у вас нет уникальной комбинации столбцов, вам не повезло. В этом случае единственный вариант - добавить новый столбец и заполнить его уникальными значениями. Если таблица достаточно мала, вы можете сделать что-то вроде этого:

ALTER TABLE dbo.pt ADD tmp_id INT IDENTITY(1,1);

Однако это займет исключительную блокировку таблицы, пока все строки не будут оценены. В зависимости от размера стола это может продолжаться довольно долго. После создания этого столбца выполните два вышеуказанных шага, чтобы сначала создать UNIQUEограничение, а затем сразу же снова его удалить. После этого вы также можете опустить столбец снова. Все эти шаги довольно навязчивы, поэтому вам лучше всего просто создать кластеризованный индекс для таблицы. Это даже не должно быть уникальным.


Если у вас есть Enterprise Edition, вы можете использовать WITH(ONLINE=ON)предложение для большинства приведенных выше утверждений. Это сделает вашу таблицу доступной для других соединений. Тем не менее, в течение этого времени будет влияние на производительность.

Себастьян Майн
источник
1
Отлично, Сабастиан! Просто отлично! Просто добавьте к # 3 выше ... если вы хотите использовать SWITCH для входа или выхода, все индексы должны быть выровнены. Создание некластеризованного, невыровненного PK не позволит вам выполнить ПЕРЕКЛЮЧЕНИЕ, если вы сначала не предпримете шаги для удаления индекса, выполнения ПЕРЕКЛЮЧЕНИЯ (в каком бы направлении оно ни находилось) и перестройки индекса. Это очень часто все еще быстрее, чем делать эквивалент с удалениями, и, конечно, если вам не нужно использовать SWITCH, это не будет проблемой.
Джефф Моден