O particionamento é um recurso poderoso no SQL Server que permite dividir tabelas grandes em partes menores e mais gerenciáveis. Uma das operações mais úteis ao trabalhar com particionamento é a operação SWITCH. Essa operação permite mover uma grande quantidade de dados de uma tabela para outra como uma operação somente de metadados, o que pode ser incrivelmente eficiente.
Uma das coisas interessantes sobre a operação SWITCH é que você pode alternar dados para uma tabela não particionada. Isso pode facilitar um pouco a sua vida, pois você não precisa gerenciar dois conjuntos de partições. No entanto, há um pequeno problema ao fazer isso, que exploraremos neste artigo.
Vamos começar criando uma tabela particionada em um banco de dados:
CREATE DATABASE [PartitioningDemo]
GO
USE [PartitioningDemo];
GO
CREATE PARTITION FUNCTION PF_PartitionedTable(DATE)
AS RANGE RIGHT
FOR VALUES ('2011-01-01','2012-01-01','2013-01-01',
'2014-01-01','2015-01-01','2016-01-01',
'2017-01-01');
GO
CREATE PARTITION SCHEME PS_PartitionedTable
AS PARTITION PF_PartitionedTable
ALL TO ([PRIMARY]);
GO
CREATE TABLE dbo.PartitionedTable
(ID INT IDENTITY(1,1),
ColA VARCHAR(10),
ColB VARCHAR(10),
CreatedDate DATE)
ON PS_PartitionedTable(CreatedDate);
GO
Agora, vamos inserir alguns dados de teste em nossa tabela particionada:
SET NOCOUNT ON;
DECLARE @FromDate date = '2011-01-01';
DECLARE @ToDate date = '2017-01-01';
INSERT INTO dbo.PartitionedTable
SELECT
REPLICATE('A',10),
REPLICATE('B',10),
DATEADD(DD,FLOOR(RAND()*(DATEDIFF(DD,@FromDate,@ToDate))),@FromDate);
GO 1000
Podemos verificar os dados e partições executando a seguinte consulta:
SELECT
p.partition_number, p.partition_id, fg.name AS [filegroup],
r.boundary_id, CONVERT(DATE,r.value) AS BoundaryValue, p.rows
FROM
sys.tables AS t
INNER JOIN
sys.indexes AS i ON t.object_id = i.object_id
INNER JOIN
sys.partitions AS p ON i.object_id = p.object_id AND i.index_id = p.index_id
INNER JOIN
sys.allocation_units a ON a.container_id = p.hobt_id
INNER JOIN
sys.filegroups fg ON fg.data_space_id = a.data_space_id
INNER JOIN
sys.partition_schemes AS s ON i.data_space_id = s.data_space_id
INNER JOIN
sys.partition_functions AS f ON s.function_id = f.function_id
LEFT OUTER JOIN
sys.partition_range_values AS r ON f.function_id = r.function_id
AND r.boundary_id = p.partition_number
WHERE
i.type <= 1 AND a.type = 1
AND
t.name = 'PartitionedTable'
ORDER BY
p.partition_number
DESC;
Agora, vamos criar uma tabela não particionada que usaremos para a operação SWITCH:
USE [PartitioningDemo];
GO
CREATE TABLE dbo.PartitionedTable_Switch
(ID INT IDENTITY(1,1),
ColA VARCHAR(10),
ColB VARCHAR(10),
CreatedDate DATE)
ON [PRIMARY];
GO
Agora, vamos realizar a operação SWITCH para mover uma das partições para a tabela de alternância:
ALTER TABLE [dbo].PartitionedTable
SWITCH PARTITION 3
TO [dbo].PartitionedTable_Switch;
GO
Neste ponto, tudo funciona como esperado. No entanto, o que acontece se precisarmos alternar os dados de volta para a tabela original?
ALTER TABLE [dbo].PartitionedTable_Switch
SWITCH
TO [dbo].PartitionedTable
PARTITION 3;
GO
Uh-oh! Encontramos uma mensagem de erro: “Msg 4982, Level 16, State 1, Line 4 ALTER TABLE SWITCH statement failed. Check constraints of source table ‘PartitioningDemo.dbo.PartitionedTable_Switch’ allow values that are not allowed by range defined by partition 3 on target table ‘PartitioningDemo.dbo.PartitionedTable’.”
Então, o que aconteceu? O problema é que estamos tentando inserir dados em uma partição que possui restrições. A partição tem um limite inferior de ‘2012-01-01’ e um limite superior de ‘2013-01-01’. Isso significa que nenhum dado pode entrar nessa partição que tenha valores no campo CreatedDate que não sejam maiores ou iguais a ‘2012-01-01’ e menores que ‘2013-01-01’. No entanto, nossa tabela de alternância não possui essas restrições.
Para resolver esse problema, precisamos informar ao SQL Server que os dados na tabela de alternância se encaixarão na partição. Podemos fazer isso removendo uma restrição da tabela:
ALTER TABLE dbo.PartitionedTable_Switch
ADD CONSTRAINT CreatedDate_Switch_CHECK CHECK
(CreatedDate >= CONVERT(DATE,'2012-01-01') AND CreatedDate < CONVERT(DATE,'2013-01-01')
AND CreatedDate IS NOT NULL);
GO
Agora, vamos tentar a operação de alternância novamente:
ALTER TABLE [dbo].PartitionedTable_Switch
SWITCH
TO [dbo].PartitionedTable
PARTITION 3;
GO
Ótimo! Os dados foram alternados com sucesso de volta para nossa tabela principal.
Portanto, embora você não precise particionar tabelas para as quais deseja alternar dados, é importante estar ciente de que, se o fizer, você precisará ser capaz de alternar esses dados de volta caso encontre algum problema. Ao entender as restrições e gerenciá-las corretamente, você pode tornar a operação SWITCH uma ferramenta poderosa em sua estratégia de particionamento do SQL Server.
Obrigado por ler!