¿Puedo mover filas entre particiones actualizando la clave de partición?

17

Creo que esta sería una pregunta bastante simple, pero en realidad he tenido dificultades para encontrar una respuesta para esto.

La pregunta: ¿puede mover filas de datos dentro de una tabla particionada de una partición a otra simplemente actualizando la columna de partición para que cruce el límite de la partición?

Por ejemplo, si tengo una tabla que tiene una clave de partición:

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

Con la función de partición que se asigna a la clave primaria:

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

¿Puedo mover una fila de la primera partición a la tercera partición cambiando el SampleID de 1 a (digamos) 500,000?

Nota: Estoy etiquetando esto como servidor SQL 2005 y 2008, ya que ambos admiten particiones. ¿Lo manejan de manera diferente?

Ricardo
fuente

Respuestas:

14

No tengo un servidor 2005 para probar. 2008, sin embargo, parece manejar esto como se esperaba:

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 ;

Debería ver un registro en cada partición antes de la actualización, y ambos registros en la primera partición después.

Kenneth
fuente
1
¡Esa es una respuesta bien hecha!
Marian
Esto también se ejecuta como usted describe en SQL Server 2005
Ben Brocka
-1 Esto no prueba el escenario. $PARTITIONsolo calcula el número de partición en función de la entrada; en realidad no prueba dónde vive físicamente la fila.
Jon Seigel
9

Para probar esto, el experimento realmente necesita particionar la tabla. Ver http://www.kodyaz.com/articles/how-to-partition-table-non-partitioned-table-sql-server-2008.aspx

La consulta de la función de partición solo le dice lo que dice la función de partición. No dice dónde se almacenan los datos. Puede configurar una función de partición y ejecutarla sin particionar una tabla, como ya se ha demostrado aquí.

Para particionar la tabla, también debe crear grupos de archivos y un esquema de partición que use la función de partición para asignar resultados de función a grupos de archivos. Luego, debe colocar una clave agrupada en la tabla que utilice ese esquema de partición.

Configurar la partición

No soy experto en línea de comandos SQL. Utilicé la interfaz SSMS para configurar grupos de archivos pfg1 (con un archivo pf1) y pfg2 (con un archivo pf2). Luego declaró la función de partición y el esquema:

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

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

Crear la tabla y el índice agrupado

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

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

Después de hacer esto, cuando consulta sys.partitions (tengo 2005), ve que la tabla ahora tiene dos particiones en lugar de solo una para la tabla. Esto indica que hemos implementado completamente la partición para esta tabla.

select * from sys.partitions where object_id = object_id('IDRanges')
Partition_id Object_id Index_id Partition_number Hobt_id filas
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
72057597780295680 770674389 1 1 72057597780295680 0
72057597780361216 770674389 1 2 72057597780361216 0

Ahora que tenemos dos particiones (con un recuento de filas para cada una), podemos realizar un experimento.

Insertar las filas

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

Consulte las particiones sys. para ver qué sucedió.

select * from sys.partitions where object_id = object_id('IDRanges')
Partition_id Object_id Index_id Partition_number Hobt_id filas
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
72057597780295680 770674389 1 1 72057597780295680 1
72057597780361216 770674389 1 2 72057597780361216 1

Sí. Una fila en cada partición.

Mueve una fila.

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

Verifica las particiones

select * from sys.partitions where object_id = object_id('IDRanges')
Partition_id Object_id Index_id Partition_number Hobt_id filas
-------------------- ----------- ----------- -------- -------- -------------------- --------------------
72057597780295680 770674389 1 1 72057597780295680 2
72057597780361216 770674389 1 2 72057597780361216 0

La primera partición ahora tiene dos filas en lugar de 1, y la segunda partición tiene cero filas en lugar de dos.

Creo que esto confirma que la fila se movió automáticamente como resultado de modificar la clave agrupada en una tabla particionada.

Jason Holladay
fuente
1
+1 para la primera respuesta a esta pregunta que realmente prueba el escenario. Bienvenido a DBA.SE!
Jon Seigel
-1 ¿Puede indicarme los documentos de MSDN que respaldan sus requisitos para particionar 'completamente' una tabla? ¿Específicamente la necesidad de grupos de archivos separados y un índice agrupado?
Kenneth
-2

No creo que esa respuesta sea correcta. Cuando usas el valor

 $PARTITION.IDRange1([ID]) AS Partition

simplemente está recalculando cuál debería ser la partición, no dónde está actualmente el registro.

Deberías usar:

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

En mis pruebas en SQL 2005, el valor cambia pero el registro permanece en la misma partición. Esto probablemente alterará las estadísticas y el optimizador, ya que se ejecutará en un modo de subprocesos múltiples esperando que una partición esté en un rango específico. También será completamente incorrecto cuando intente utilizar la eliminación de la partición para consultar solo la partición relevante. Creo que debe eliminar y volver a insertar cada registro para que se muevan.

Steve Ledridge
fuente
2
La búsqueda de $partition aquí sugiere que la respuesta aceptada es correcta. ¿Cómo confirma que el registro permanece en la misma partición después de haber sido actualizado?
Nick Chammas
El primer punto es cierto, pero la conclusión de que la fila no se mueve es falsa, presumiblemente hay algo mal con la prueba que se ejecutó.
Jon Seigel