Posso mover linhas entre partições atualizando a chave da partição?

17

Eu pensaria que essa seria uma pergunta bastante simples, mas realmente tive dificuldade em encontrar uma resposta para isso.

A pergunta: você pode mover linhas de dados dentro de uma tabela particionada de uma partição para outra, simplesmente atualizando a coluna da partição para que ela atravesse o limite da partição?

Por exemplo, se eu tiver uma tabela que tenha uma chave de partição:

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

Com a função de partição que mapeia para a chave primária:

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

Posso mover uma linha da primeira partição para a terceira partição, alterando o SampleID de 1 para (digamos) 500.000?

Nota: estou marcando isso como sql server 2005 e 2008, pois ambos oferecem suporte ao particionamento. Eles lidam com isso de maneira diferente?

Richard
fonte

Respostas:

14

Eu não tenho um servidor de 2005 para testar. 2008, no entanto, parece lidar com isso conforme o esperado:

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 ;

Você deve ver um registro em cada partição antes da atualização e os dois registros na primeira partição posteriormente.

Kenneth
fonte
1
essa é uma resposta bem feita!
Marian
Isso é executado como você descreve no SQL Server 2005 também
Ben Brocka
-1 Isso não testa o cenário. $PARTITIONcalcula apenas o número da partição com base na entrada; na verdade, não testa onde a linha vive fisicamente.
Jon Seigel
9

Para testar isso, o experimento realmente precisa particionar a tabela. Consulte http://www.kodyaz.com/articles/how-to-partition-table-non-partitioned-table-sql-server-2008.aspx

Consultar a função de particionamento apenas informa o que a função de particionamento diz. Não diz onde os dados estão armazenados. Você pode configurar uma função de particionamento e executá-la sem realmente particionar uma tabela, como já foi demonstrado aqui.

Para particionar a tabela, você também precisa criar grupos de arquivos e um esquema de particionamento que use a função de particionamento para atribuir resultados da função a grupos de arquivos. Então você deve colocar uma chave em cluster na tabela que usa esse esquema de particionamento.

Configure o particionamento

Não sou especialista em SQL de linha de comando. Usei a interface SSMS para configurar os grupos de arquivos pfg1 (com um arquivo pf1) e pfg2 (com um arquivo pf2). Então eu declarei a função e o esquema de particionamento:

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

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

Crie a tabela e o índice clusterizado

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

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

Depois de fazer isso, quando você consulta sys.partitions (eu tenho 2005), você vê que a tabela agora tem duas partições em vez de apenas uma para a tabela. Isso indica que implementamos totalmente o particionamento para esta tabela.

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

Agora que temos duas partições (com uma contagem de linhas para cada uma), podemos realizar um experimento.

Inserir as linhas

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

Verifique as partições sys. para ver o que aconteceu.

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

Sim. Uma linha em cada partição.

Mover uma linha.

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

Verifique as partições

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

A primeira partição agora tem duas linhas em vez de 1 e a segunda partição tem zero linhas em vez de duas.

Eu acho que isso confirma que a linha foi movida automaticamente como resultado da modificação da chave em cluster em uma tabela particionada.

Jason Holladay
fonte
1
+1 na primeira resposta a esta pergunta que realmente testa o cenário. Bem-vindo ao DBA.SE!
quer
-1 Você pode me indicar os documentos do MSDN que suportam seus requisitos para particionar 'completamente' uma tabela? Especificamente, a necessidade de grupos de arquivos separados e um índice em cluster?
19413 Kenneth
-2

Não acho que essa resposta esteja correta. Quando você usa o valor

 $PARTITION.IDRange1([ID]) AS Partition

você está simplesmente recalculando qual deve ser a partição, não onde está o registro atualmente.

Você deveria usar:

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

Nos meus testes no sql 2005, o valor muda, mas o registro permanece na mesma partição. Provavelmente, isso mexerá com as estatísticas e com o otimizador, pois ele será executado em um modo multiencadeado, esperando que uma partição esteja em um intervalo específico. Também estará completamente errado quando tentar usar a eliminação da partição para consultar apenas a partição relevante. Eu acho que você precisa excluir e reinserir cada registro para que eles se movam.

Steve Ledridge
fonte
2
Procurar $partition aqui sugere que a resposta aceita está correta. Como você está confirmando que o registro permanece na mesma partição após a atualização?
Nick Chammas
O primeiro ponto é verdadeiro, mas a conclusão de que a linha não se move é falsa - presumivelmente há algo errado com o teste que foi executado.
quer