Czy mogę przenosić wiersze między partycjami, aktualizując klucz partycji?

17

Sądzę, że byłoby to dość proste pytanie, ale tak naprawdę miałem trudności ze znalezieniem odpowiedzi na to pytanie.

Pytanie: Czy możesz przenosić wiersze danych w tabeli podzielonej na partycje z jednej partycji do drugiej, po prostu aktualizując kolumnę partycji, tak aby przekraczała granicę partycji?

Na przykład, jeśli mam tabelę z kluczem partycji:

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

Dzięki funkcji partycji mapowanej na klucz podstawowy:

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

Czy mogę przenieść wiersz z pierwszej partycji do trzeciej partycji, zmieniając SampleID z 1 na (powiedzmy) 500 000?

Uwaga: Oznaczam to jako serwer SQL 2005 i 2008, ponieważ oba obsługują partycjonowanie. Czy traktują to inaczej?

Richard
źródło

Odpowiedzi:

14

Nie mam serwera 2005 do testowania. Wydaje się jednak, że w 2008 r. Rozwiązano to zgodnie z oczekiwaniami:

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 ;

Powinieneś zobaczyć jeden rekord na każdej partycji przed aktualizacją i oba rekordy na pierwszej partycji później.

Kenneth
źródło
1
to ładnie wykonana odpowiedź!
Marian,
Wykonuje się to tak, jak opisano w SQL Server 2005
Ben Brocka,
-1 To nie testuje scenariusza. $PARTITIONoblicza tylko numer partycji na podstawie danych wejściowych; tak naprawdę nie sprawdza, gdzie fizycznie żyje rząd.
Jon Seigel
9

Aby to przetestować, eksperyment faktycznie musi podzielić tabelę. Zobacz http://www.kodyaz.com/articles/how-to-partition-table-non-partitioned-table-sql-server-2008.aspx

Zapytanie o funkcję partycjonowania mówi ci tylko, co mówi funkcja partycjonowania. Nie mówi, gdzie są przechowywane dane. Możesz skonfigurować funkcję partycjonowania i uruchomić ją bez partycjonowania tabeli, jak już tutaj pokazano.

Aby podzielić tabelę na partycje, musisz także utworzyć grupy plików i schemat partycjonowania, który używa funkcji partycjonowania do przypisywania wyników funkcji do grup plików. Następnie musisz umieścić klucz klastrowany w tabeli korzystającej z tego schematu partycjonowania.

Skonfiguruj partycjonowanie

Nie jestem ekspertem od SQL wiersza poleceń. Użyłem interfejsu SSMS, aby skonfigurować grupy plików pfg1 (z plikiem pf1) i pfg2 (z plikiem pf2). Następnie zadeklarowałem funkcję i schemat partycjonowania:

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

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

Utwórz tabelę i indeks klastrowany

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

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

Gdy to zrobisz, po zapytaniu o sys.partitions (mam 2005), zobaczysz, że tabela ma teraz dwie partycje zamiast tylko jednej dla tabeli. Oznacza to, że w pełni zaimplementowaliśmy partycjonowanie dla tej tabeli.

select * from sys.partitions where object_id = object_id('IDRanges')
identyfikator_partycji identyfikator_obiektu identyfikator_indeksu numer_partycji identyfikator_oboju wiersze
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
72057597780295680 770674389 1 1 72057597780295680 0
72057597780361216 770674389 1 2 72057597780361216 0

Teraz, gdy mamy dwie partycje (z liczbą wierszy dla każdej), możemy przeprowadzić eksperyment.

Wstaw rzędy

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

Sprawdź sys.partitions, aby zobaczyć, co się stało.

select * from sys.partitions where object_id = object_id('IDRanges')
identyfikator_partycji identyfikator_obiektu identyfikator_indeksu numer_partycji identyfikator_oboju wiersze
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
72057597780295680 770674389 1 1 72057597780295680 1
72057597780361216 770674389 1 2 72057597780361216 1

Tak. Jeden rząd w każdej partycji.

Przenieś rząd.

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

Sprawdź partycje

select * from sys.partitions where object_id = object_id('IDRanges')
identyfikator_partycji identyfikator_obiektu identyfikator_indeksu numer_partycji identyfikator_oboju wiersze
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
72057597780295680 770674389 1 1 72057597780295680 2
72057597780361216 770674389 1 2 72057597780361216 0

Pierwsza partycja ma teraz dwa wiersze zamiast 1, a druga partycja ma zero wierszy zamiast dwóch.

Myślę, że to potwierdza, że ​​wiersz został automatycznie przeniesiony w wyniku modyfikacji klucza klastrowego w tabeli podzielonej na partycje.

Jason Holladay
źródło
1
+1 za pierwszą odpowiedź na to pytanie, która faktycznie testuje scenariusz. Witamy w DBA.SE!
Jon Seigel
-1 Czy możesz wskazać mi dokumenty MSDN, które spełniają twoje wymagania dotyczące „pełnego” podziału tabeli na partycje? W szczególności potrzeba oddzielnych grup plików i indeksu klastrowego?
Kenneth,
-2

Nie sądzę, aby ta odpowiedź była poprawna. Gdy użyjesz tej wartości

 $PARTITION.IDRange1([ID]) AS Partition

po prostu przeliczasz, jaka powinna być partycja, a nie miejsce, w którym aktualnie znajduje się rekord.

Powinieneś użyć:

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

W moich testach na SQL 2005 wartość zmienia się, ale rekord pozostaje na tej samej partycji. Prawdopodobnie spowoduje to bałagan ze statystykami i optymalizatorem, ponieważ będzie działał w trybie wielowątkowym, oczekując, że partycja będzie w określonym zakresie. Będzie to również całkowicie błędne, gdy spróbuje użyć eliminacji partycji do zapytania tylko o odpowiednią partycję. Myślę, że musisz usunąć i ponownie wstawić każdy rekord, aby go przenieść.

Steve Ledridge
źródło
2
Wyszukiwanie $partition tutaj sugeruje, że zaakceptowana odpowiedź jest poprawna. W jaki sposób potwierdzasz, że rekord pozostaje na tej samej partycji po jego aktualizacji?
Nick Chammas,
Pierwszy punkt jest prawdziwy, ale wniosek, że rząd się nie porusza, jest fałszywy - przypuszczalnie jest coś nie tak z uruchomionym testem.
Jon Seigel