Puis-je déplacer des lignes entre des partitions en mettant à jour la clé de partition?

17

Je pense que ce serait une question assez simple, mais j'ai en fait eu du mal à trouver une réponse à cela.

La question: pouvez-vous déplacer des lignes de données dans une table partitionnée d'une partition à une autre en mettant simplement à jour la colonne de partition afin qu'elle traverse la frontière de la partition?

Par exemple, si j'ai une table qui a une clé de partition:

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

Avec la fonction de partition qui correspond à la clé primaire:

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

Puis-je déplacer une ligne de la première partition à la troisième partition en changeant le SampleID de 1 à (disons) 500 000?

Remarque: Je marque ceci comme serveur SQL 2005 et 2008, car ils prennent tous les deux en charge le partitionnement. Le traitent-ils différemment?

Richard
la source

Réponses:

14

Je n'ai pas de serveur 2005 pour tester. 2008 semble cependant gérer cela comme prévu:

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 ;

Vous devriez voir un enregistrement dans chaque partition avant la mise à jour et les deux enregistrements dans la première partition après.

Kenneth
la source
1
c'est une réponse bien faite!
Marian
Cela s'exécute également comme vous le décrivez dans SQL Server 2005
Ben Brocka
-1 Cela ne teste pas le scénario. $PARTITIONcalcule uniquement le numéro de partition en fonction de l'entrée; il ne teste pas réellement où la rangée vit physiquement.
Jon Seigel
9

Pour tester cela, l'expérience doit réellement partitionner la table. Voir http://www.kodyaz.com/articles/how-to-partition-table-non-partitioned-table-sql-server-2008.aspx

L'interrogation de la fonction de partitionnement vous indique simplement ce que dit la fonction de partitionnement. Il ne dit pas où les données sont stockées. Vous pouvez configurer une fonction de partitionnement et l'exécuter sans réellement partitionner une table, comme cela a déjà été démontré ici.

Pour partitionner la table, vous devez également créer des groupes de fichiers et un schéma de partitionnement qui utilise la fonction de partitionnement pour affecter des résultats de fonction aux groupes de fichiers. Ensuite, vous devez mettre une clé en cluster sur la table qui utilise ce schéma de partitionnement.

Configurer le partitionnement

Je ne suis pas un expert en ligne de commande SQL. J'ai utilisé l'interface SSMS pour configurer les groupes de fichiers pfg1 (avec un fichier pf1) et pfg2 (avec un fichier pf2). Ensuite, j'ai déclaré la fonction et le schéma de partitionnement:

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

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

Créer la table et l'index clusterisé

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

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

Après cela, lorsque vous interrogez sys.partitions (j'ai 2005), vous voyez que la table a maintenant deux partitions au lieu d'une seule pour la table. Cela indique que nous avons entièrement implémenté le partitionnement pour cette table.

select * from sys.partitions where object_id = object_id('IDRanges')
id_partition id_objet index_id numéro_partition hobt_id lignes
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
72057597780295680 770674389 1 1 72057597780295680 0
72057597780361216 770674389 1 2 72057597780361216 0

Maintenant que nous avons deux partitions (avec un nombre de lignes pour chacune), nous pouvons mener une expérience.

Insérez les lignes

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

Vérifiez les partitions sys.pour voir ce qui s'est passé.

select * from sys.partitions where object_id = object_id('IDRanges')
id_partition id_objet index_id numéro_partition hobt_id lignes
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
72057597780295680 770674389 1 1 72057597780295680 1
72057597780361216 770674389 1 2 72057597780361216 1

Oui. Une ligne dans chaque partition.

Déplacez une rangée.

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

Vérifiez les partitions

select * from sys.partitions where object_id = object_id('IDRanges')
id_partition id_objet index_id numéro_partition hobt_id lignes
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
72057597780295680 770674389 1 1 72057597780295680 2
72057597780361216 770674389 1 2 72057597780361216 0

La première partition a maintenant deux lignes au lieu de 1, et la deuxième partition a zéro ligne au lieu de deux.

Je pense que cela confirme que la ligne a été automatiquement déplacée suite à la modification de la clé en cluster dans une table partitionnée.

Jason Holladay
la source
1
+1 pour la première réponse à cette question qui teste réellement le scénario. Bienvenue sur DBA.SE!
Jon Seigel
-1 Pouvez-vous s'il vous plaît me pointer vers les documents MSDN qui prennent en charge vos exigences pour partitionner «entièrement» une table? Plus précisément, la nécessité de groupes de fichiers séparés et d'un index clusterisé?
Kenneth
-2

Je ne pense pas que cette réponse soit correcte. Lorsque vous utilisez la valeur

 $PARTITION.IDRange1([ID]) AS Partition

vous recalculez simplement ce que devrait être la partition, et non l'emplacement actuel de l'enregistrement.

Tu devrais utiliser:

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

Dans mes tests sur sql 2005, la valeur change mais le record reste dans la même partition. Cela gâchera probablement les statistiques et l'optimiseur car il s'exécutera en mode multi-thread, en attendant qu'une partition soit dans une plage spécifique. Il sera également complètement faux lorsqu'il essaiera d'utiliser l'élimination de partition pour interroger uniquement la partition appropriée. Je pense que vous devez supprimer et réinsérer chaque enregistrement pour les faire bouger.

Steve Ledridge
la source
2
La recherche $partition ici suggère que la réponse acceptée est correcte. Comment confirmez-vous que l'enregistrement reste dans la même partition après sa mise à jour?
Nick Chammas
Le premier point est vrai, mais la conclusion que la ligne ne bouge pas est fausse - il y a probablement un problème avec le test qui a été exécuté.
Jon Seigel