Kann ich Zeilen zwischen Partitionen verschieben, indem ich den Partitionsschlüssel aktualisiere?

17

Ich würde denken, dass dies eine ziemlich einfache Frage wäre, aber ich hatte tatsächlich Schwierigkeiten, eine Antwort darauf zu finden.

Die Frage: Können Sie Datenzeilen innerhalb einer partitionierten Tabelle von einer Partition in eine andere verschieben, indem Sie einfach die Partitionsspalte so aktualisieren, dass sie die Partitionsgrenze überschreitet?

Wenn ich zum Beispiel eine Tabelle mit einem Partitionsschlüssel habe:

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

Mit der Partitionsfunktion, die dem Primärschlüssel zugeordnet ist:

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

Kann ich eine Zeile von der ersten Partition auf die dritte Partition verschieben, indem ich die SampleID von 1 auf (sagen wir) 500.000 ändere?

Hinweis: Ich bezeichne dies als SQL Server 2005 und 2008, da beide die Partitionierung unterstützen. Gehen sie anders damit um?

Richard
quelle

Antworten:

14

Ich habe keinen 2005-Server zum Testen. 2008 scheint dies jedoch wie erwartet zu handhaben:

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 ;

Vor dem Update sollte in jeder Partition ein Datensatz und danach in der ersten Partition beide Datensätze angezeigt werden.

Kenneth
quelle
1
das ist eine schön gemachte Antwort!
Marian
Dies wird ausgeführt, wie Sie es auch in SQL Server 2005 beschrieben haben
Ben Brocka,
-1 Dies testet das Szenario nicht. $PARTITIONberechnet nur die Partitionsnummer basierend auf der Eingabe; Es wird nicht überprüft, wo die Zeile physisch lebt.
Jon Seigel
9

Um dies zu testen, muss das Experiment die Tabelle tatsächlich partitionieren. Siehe http://www.kodyaz.com/articles/how-to-partition-table-non-partitioned-table-sql-server-2008.aspx

Wenn Sie die Partitionierungsfunktion abfragen, erfahren Sie nur, was die Partitionierungsfunktion sagt. Es sagt nicht, wo die Daten gespeichert sind. Sie können eine Partitionierungsfunktion einrichten und ausführen, ohne eine Tabelle zu partitionieren, wie hier bereits gezeigt wurde.

Um die Tabelle zu partitionieren, müssen Sie auch Dateigruppen und ein Partitionierungsschema erstellen, das die Partitionierungsfunktion verwendet, um Funktionsergebnisse Dateigruppen zuzuweisen. Dann müssen Sie einen gruppierten Schlüssel in die Tabelle einfügen, der dieses Partitionsschema verwendet.

Richten Sie die Partitionierung ein

Ich bin kein Experte für Befehlszeilen-SQL. Ich habe die SSMS-Schnittstelle verwendet, um die Dateigruppen pfg1 (mit einer pf1-Datei) und pfg2 (mit einer pf2-Datei) einzurichten. Dann habe ich die Partitionierungsfunktion und das Schema deklariert:

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

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

Erstellen Sie die Tabelle und den Clustered-Index

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

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

Wenn Sie danach sys.partitions abfragen (ich habe 2005), sehen Sie, dass die Tabelle jetzt zwei Partitionen anstelle nur einer für die Tabelle enthält. Dies zeigt an, dass die Partitionierung für diese Tabelle vollständig implementiert wurde.

select * from sys.partitions where object_id = object_id('IDRanges')
partition_id object_id index_id partition_number hobt_id Zeilen
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
72057597780295680 770674389 1 1 72057597780295680 0
72057597780361216 770674389 1 2 72057597780361216 0

Nun, da wir zwei Partitionen haben (mit einer Zeilenanzahl für jede), können wir ein Experiment durchführen.

Fügen Sie die Zeilen ein

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

Überprüfen Sie die sys.partitions, um zu sehen, was passiert ist.

select * from sys.partitions where object_id = object_id('IDRanges')
partition_id object_id index_id partition_number hobt_id Zeilen
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
72057597780295680 770674389 1 1 72057597780295680 1
72057597780361216 770674389 1 2 72057597780361216 1

Ja. Eine Zeile in jeder Partition.

Eine Reihe verschieben.

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

Überprüfen Sie die Partitionen

select * from sys.partitions where object_id = object_id('IDRanges')
partition_id object_id index_id partition_number hobt_id Zeilen
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
72057597780295680 770674389 1 1 72057597780295680 2
72057597780361216 770674389 1 2 72057597780361216 0

Die erste Partition hat jetzt zwei Zeilen anstelle von 1 und die zweite Partition hat null Zeilen anstelle von zwei.

Ich denke, dies bestätigt, dass die Zeile automatisch aufgrund der Änderung des gruppierten Schlüssels in einer partitionierten Tabelle verschoben wurde.

Jason Holladay
quelle
1
+1 für die erste Antwort auf diese Frage, die das Szenario tatsächlich testet. Willkommen bei DBA.SE!
Jon Seigel
-1 Zeigen Sie mir bitte die MSDN-Dokumente, die Ihre Anforderungen für die vollständige Partitionierung einer Tabelle erfüllen. Speziell die Notwendigkeit für separate Dateigruppen und einen Clustered-Index?
Kenneth
-2

Ich denke nicht, dass diese Antwort richtig ist. Wenn Sie den Wert verwenden

 $PARTITION.IDRange1([ID]) AS Partition

Sie berechnen einfach neu, was die Partition sein soll, und nicht, wo sich der Datensatz gerade befindet.

Du solltest benutzen:

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

In meinen Tests auf SQL 2005 ändert sich der Wert, aber der Datensatz bleibt auf derselben Partition. Dies führt wahrscheinlich zu Problemen mit den Statistiken und dem Optimierer, da dieser in einem Multithread-Modus ausgeführt wird und erwartet, dass sich eine Partition in einem bestimmten Bereich befindet. Es ist auch völlig falsch, wenn versucht wird, die Partitionseliminierung zu verwenden, um nur die relevante Partition abzufragen. Ich denke, Sie müssen jeden Datensatz löschen und neu einfügen, damit er verschoben wird.

Steve Ledridge
quelle
2
Wenn $partition Sie hier nach suchen, ist die akzeptierte Antwort richtig. Wie bestätigen Sie, dass sich der Datensatz nach der Aktualisierung in derselben Partition befindet?
Nick Chammas
Der erste Punkt ist wahr, aber die Schlussfolgerung, dass sich die Zeile nicht bewegt, ist falsch - vermutlich stimmt etwas mit dem durchgeführten Test nicht.
Jon Seigel