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.