Можно ли перемещать строки между разделами, обновляя ключ раздела?

17

Я думаю, что это будет довольно простой вопрос, но на самом деле мне было трудно найти ответ на этот вопрос.

Вопрос: Можете ли вы переместить строки данных в разделенной таблице из одного раздела в другой, просто обновив столбец раздела так, чтобы он пересекал границу раздела?

Например, если у меня есть таблица с ключом раздела:

CREATE TABLE SampleTable
(
    SampleID INT PRIMARY KEY,
    SampleResults VARCHAR(100) NOT NULL,
)

С функцией разделения, которая отображается на первичный ключ:

CREATE PARTITION FUNCTION MyPartitionFunc (INT) AS
RANGE LEFT FOR VALUES (10000, 20000);

Можно ли переместить строку из первого раздела в третий, изменив SampleID с 1 на (скажем) 500 000?

Примечание: я отмечаю это как SQL Server 2005 и 2008, так как они оба поддерживают разбиение. Они справляются с этим по-другому?

Ричард
источник

Ответы:

14

У меня нет сервера 2005 года для тестирования. 2008, однако, кажется, справиться с этим, как ожидалось

USE [Test]
GO
CREATE TABLE [IDRanges](
    [ID] [int] NOT NULL
)
GO

CREATE PARTITION FUNCTION IDRange1 (int)
AS RANGE LEFT FOR VALUES (10) ;
GO
--Add one record to each partition
INSERT INTO IDRanges ([ID]) VALUES (17)
INSERT INTO IDRanges ([ID]) VALUES (7)
GO
--Verify records in partition
SELECT $PARTITION.IDRange1([ID]) AS Partition, COUNT(*) AS [COUNT] 
FROM IDRanges
GROUP BY $PARTITION.IDRange1([ID]) 
ORDER BY Partition ;
GO
--Move row between partitions
UPDATE IDRanges
SET [ID] = 8 WHERE [ID] = 17
GO
--Verify records in partition
SELECT $PARTITION.IDRange1([ID]) AS Partition, COUNT(*) AS [COUNT] 
FROM IDRanges
GROUP BY $PARTITION.IDRange1([ID]) 
ORDER BY Partition ;

Вы должны увидеть одну запись в каждом разделе перед обновлением и обе записи в первом разделе после.

Кеннет
источник
1
это красиво сделанный ответ!
Marian
Это выполняется так же, как вы описали в SQL Server 2005
Бен Брока
-1 Это не проверяет сценарий. $PARTITIONвычисляет только номер раздела на основе ввода; это фактически не проверяет, где физически живет ряд.
Джон Зигель
9

Чтобы проверить это, эксперимент должен фактически разделить таблицу. См. Http://www.kodyaz.com/articles/how-to-partition-table-non-partitioned-table-sql-server-2008.aspx

Запрос функции разделения просто говорит вам, что говорит функция разделения. Там не сказано, где хранятся данные. Вы можете настроить функцию разделения и запустить ее без фактического разделения таблицы, как уже было продемонстрировано здесь.

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

Настройте разделение

Я не эксперт в командной строке SQL. Я использовал интерфейс SSMS для настройки групп файлов pfg1 (с файлом pf1) и pfg2 (с файлом pf2). Затем я объявил функцию разделения и схему:

CREATE PARTITION FUNCTION IDRange1 (int)
AS RANGE LEFT FOR VALUES (10) ;
GO

CREATE PARTITION SCHEME ps_IDRange1
AS PARTITION IDRange1
TO (pfg1, pfg2)
GO

Создать таблицу и кластерный индекс

CREATE TABLE [IDRanges](
    [ID] [int] NOT NULL
)
GO

CREATE CLUSTERED INDEX PK_IDRanges
ON dbo.IDRanges(id) ON ps_IDRange1 (ID)
GO

После того, как вы это сделаете, когда вы запросите sys.partitions (у меня есть 2005), вы увидите, что в таблице теперь есть два раздела вместо одного для таблицы. Это указывает на то, что мы полностью реализовали разбиение для этой таблицы.

select * from sys.partitions where object_id = object_id('IDRanges')
идентификатор_раздела_идентификатор_объекта
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
72057597780295680 770674389 1 1 72057597780295680 0
72057597780361216 770674389 1 2 72057597780361216 0

Теперь, когда у нас есть два раздела (с количеством строк для каждого), мы можем провести эксперимент.

Вставьте строки

INSERT INTO IDRanges ([ID]) VALUES (17)
INSERT INTO IDRanges ([ID]) VALUES (7)

Проверьте sys.partitions, чтобы увидеть, что случилось.

select * from sys.partitions where object_id = object_id('IDRanges')
идентификатор_раздела_идентификатор_объекта
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
72057597780295680 770674389 1 1 72057597780295680 1
72057597780361216 770674389 1 2 72057597780361216 1

Ага. Одна строка в каждом разделе.

Переместить ряд.

UPDATE IDRanges
SET [ID] = 8 WHERE [ID] = 17

Проверьте разделы

select * from sys.partitions where object_id = object_id('IDRanges')
идентификатор_раздела_идентификатор_объекта
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
72057597780295680 770674389 1 1 72057597780295680 2
72057597780361216 770674389 1 2 72057597780361216 0

Первый раздел теперь имеет две строки вместо 1, а второй раздел имеет нулевые строки вместо двух.

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

Джейсон Холладей
источник
1
+1 за первый ответ на этот вопрос, который фактически проверяет сценарий. Добро пожаловать в DBA.SE!
Джон Зигель
-1 Не могли бы вы указать мне документы MSDN, которые поддерживают ваши требования для «полного» разбиения таблицы? В частности, необходимость отдельных файловых групп и кластеризованного индекса?
Кеннет
-2

Я не думаю, что ответ правильный. Когда вы используете значение

 $PARTITION.IDRange1([ID]) AS Partition

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

Вы должны использовать:

select * from sys.partitions where object_id = object_id('IDRanges')

В моих тестах на SQL 2005 значение меняется, но запись остается в том же разделе. Вероятно, это будет мешать статистике и оптимизатору, так как он будет работать в многопоточном режиме, ожидая, что раздел находится в определенном диапазоне. Это также будет совершенно неправильно, если он попытается использовать удаление разделов только для запроса соответствующего раздела. Я думаю, что вам нужно удалить и заново вставить каждую запись, чтобы заставить их двигаться.

Стив Ледридж
источник
2
Поиск $partition здесь предполагает, что принятый ответ является правильным. Как вы подтверждаете, что запись остается в том же разделе после ее обновления?
Ник Чаммас
Первый пункт верен, но вывод о том, что строка не перемещается, неверен - возможно, что-то не так с выполненным тестом.
Джон Зигель