Чи можна переміщувати рядки між розділами, оновивши ключ розділу?


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 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
це чудово зроблена відповідь!
Маріан

Це виконується так, як ви описуєте в SQL Server 2005, а також
Бен Брокка,

-1 Це не перевіряє сценарій. $PARTITIONобчислює лише номер розділу на основі вхідних даних; він насправді не перевіряє, де фізично живе рядок.
Джон Сейгель

9

Для перевірки цього експерименту насправді потрібно розділити таблицю. Дивіться http://www.kodyaz.com/articles/how-to-partition-table-non-partified-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')
partition_id object_id index_id partition_number рядки hobt_id
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
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')
partition_id object_id index_id partition_number рядки hobt_id
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
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')
partition_id object_id index_id partition_number рядки hobt_id
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
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 тут, говорить про те, що прийнята відповідь є правильною. Як ви підтверджуєте, що запис залишається в тому ж розділі після оновлення?
Нік Чаммас

Перший пункт правдивий, але висновок про те, що рядок не переміщується, є помилковим - мабуть, у тесті, який був запущений, щось не так.
Джон Сейгель
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.