ALTER TABLE… Falha na alternância da tabela regular para a tabela particionada


9

O código abaixo faz o seguinte:

  1. Cria um banco de dados play_partition em C: \ TEMP
  2. Cria duas tabelas particionadas idênticas play_table e archive_play_table
  3. Muda a partição play_table 1 para a partição archive_play_table 1
  4. Cria uma nova tabela não particionada temp_table com a mesma estrutura que play_table no mesmo grupo de arquivos da partição play_table 2
  5. Muda play_table_partition 2 para temp_table
  6. Tenta alternar temp_table de volta para a partição play_table 2 e falha com

    Mensagem 4982, nível 16, estado 1, linha 64 A instrução ALTER TABLE SWITCH falhou. Verifique as restrições da tabela de origem 'play_partition.dbo.temp_table' permitindo valores que não são permitidos pelo intervalo definido pela partição 2 na tabela de destino 'play_partition.dbo.play_table'.

Por que falha?

Estou usando o SQL Server 2014 (Enterprise Edition Trial).

Saudações,

Colin Daley

http://www.colindaley.com/translator

/* Playing with partitioned tables */

USE master;
GO

DROP DATABASE play_partition;
GO

CREATE DATABASE play_partition
    ON PRIMARY(
        NAME = play_partition
        , FILENAME = 'C:\TEMP\play_partition.mdf')
    ,FILEGROUP play_fg1(
        NAME = play_fg1
        ,FILENAME = 'C:\TEMP\play_fg1f1.ndf')
    ,FILEGROUP play_fg2(
        NAME = play_fg2f1
        ,FILENAME = 'C:\TEMP\play_fg2f1.ndf');
GO

USE play_partition;


CREATE PARTITION FUNCTION play_range(INT)
    AS RANGE LEFT FOR VALUES(3);

-- Partition scheme
CREATE PARTITION SCHEME play_scheme 
    AS PARTITION play_range TO (play_fg1, play_fg2);

-- Partitioned tables
CREATE TABLE dbo.play_table(
    c1 INT NOT NULL CONSTRAINT PK_play_table_c1 PRIMARY KEY CLUSTERED
)
    ON play_scheme(c1);

CREATE TABLE dbo.archive_play_table(
c1 INT NOT NULL CONSTRAINT PK_archive_play_table_c1 PRIMARY KEY CLUSTERED
)
    ON play_scheme(c1);

-- partition 1 = {1, 2, 3}, partiion 2 = {4, 5, 6}
INSERT INTO dbo.play_table(c1) VALUES (1), (2),  (3), (4), (5), (6);

-- move partition 1 from play_table to archive play_table
ALTER TABLE dbo.play_table
    SWITCH PARTITION 1 to dbo.archive_play_table PARTITION 1;

-- create empty table with same structure as dbo.play_table
SELECT * INTO dbo.temp_table FROM dbo.play_table WHERE 1 = 0;

-- move temp_table to filegroup play_fg2
ALTER TABLE dbo.temp_table
    ADD CONSTRAINT PK_temp_table_c1 PRIMARY KEY CLUSTERED(c1) ON play_fg2;

-- move contents of play_table to temp_table, which is not partitioned
-- but is in the same filegroup
ALTER TABLE dbo.play_table
    SWITCH PARTITION 2 TO temp_table;
PRINT 'Switched from partitioned table to non-partitioned table';

-- move data back to partitioned play_table from unpartitioned temp_table
-- FAIL
ALTER TABLE dbo.temp_table
    SWITCH TO play_table partition 2;
PRINT 'Switched from non-partitioned table to partitioned table';


SELECT 'archive_play_table' as table_name, t1.c1
    FROM dbo.archive_play_table AS t1
    UNION ALL
    SELECT 'temp_table' AS table_name, t1.c1
        FROM dbo.temp_table as t1
    ORDER BY 1, 2;

+1 na sua pergunta. Você facilitou a reprodução e a resposta, devido ao DDL que você colocou aqui. Por isso, obrigado. Eu gostaria de poder +10 perguntas como esta.
— 8788 Thomas Stringer

Obrigado. Esse erro precisa de uma mensagem melhor. Quando mencionou restrições de verificação na tabela (quando não havia restrição de verificação), não me ocorreu que a falta de uma restrição de verificação fosse, de fato, o problema.
— Colin Daley

Respostas:


11

Quando você estiver trabalhando com a alternância de partições, o SQL Server precisará verificar se os limites da tabela / partição de origem podem caber nos limites da tabela / partição de destino. Em outras palavras, você está tentando dados mudar do dbo.temp_tableque dbo.play_table's partição 2. Pense nisso como este, os dados para o c1no dbo.temp_tableé limitada apenas pelo tipo de dados ( int), assim você pode ter valores que variam de-2,147,483,648 a 2.147.483.647 . Por outro lado, seu destino ( dbo.play_tablepartição 2) tem um intervalo de 4 a 2.147.483.647.

Seus dados não violam isso, mas são os metadados que não podem permitir isso. Você poderia facilmente inserir o valor -10 em dbo.temp_table. A troca de partição falharia da mesma maneira e faria mais sentido, pois -10 não se encaixa nos dbo.play_tablelimites da 2ª partição.

Se você quisesse fazer esse código funcionar, seria necessário informar explicitamente ao SQL Server que dbo.temp_tablenunca haverá dados que não se encaixem na dbo.play_table2ª partição. Você pode fazer isso com uma restrição de verificação:

/******************************************************************************
    your code omitted for brevity
******************************************************************************/

-- move contents of play_table to temp_table, which is not partitioned
-- but is in the same filegroup
ALTER TABLE dbo.play_table
    SWITCH PARTITION 2 TO temp_table;
PRINT 'Switched from partitioned table to non-partitioned table';

/******************************************************************************
    added check constraint so that data can fit in the destination partition
******************************************************************************/
alter table dbo.temp_table
add constraint CK_TempTable_C1 check (c1 >= 4);
go
/******************************************************************************
    end of added code
******************************************************************************/

-- move data back to partitioned play_table from unpartitioned temp_table
-- this will no longer FAIL
ALTER TABLE dbo.temp_table
    SWITCH TO play_table partition 2;
PRINT 'Switched from non-partitioned table to partitioned table';

/******************************************************************************
    your code omitted for brevity
******************************************************************************/

A adição de amostra acima ao seu código torna essa uma solução funcional. Agora, o SQL Server sabe que os dados dbo.temp_tablepodem caber na partição 2 dbo.play_tabledevido à restrição de verificação adicionada a dbo.temp_table.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.