ALTER TABLE ... LA CONMUTACIÓN de la tabla normal a la tabla particionada falla

9

El siguiente código hace lo siguiente:

  1. Crea una base de datos play_partition en C: \ TEMP
  2. Crea dos tablas particionadas idénticas play_table y archive_play_table
  3. Cambia la partición play_table 1 a la partición archive_play_table 1
  4. Crea una nueva tabla no particionada temp_table con la misma estructura que play_table en el mismo grupo de archivos que play_table partición 2
  5. Cambia play_table_partition 2 a temp_table
  6. Intenta cambiar temp_table de nuevo a play_table partición 2 y falla con

    Mensaje 4982, Nivel 16, Estado 1, Línea 64 La instrucción ALTER TABLE SWITCH falló. Compruebe las restricciones de la tabla de origen 'play_partition.dbo.temp_table' para permitir valores que no están permitidos por el rango definido por la partición 2 en la tabla de destino 'play_partition.dbo.play_table'.

¿Por qué falla?

Estoy usando SQL Server 2014 (versión de prueba de Enterprise Edition).

Saludos,

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;
Colin Daley
fuente
+1 en tu pregunta. Usted facilitó la reprobación y la respuesta, debido al DDL que puso aquí. Por eso, gracias. Desearía poder hacer +10 preguntas como esta.
Thomas Stringer
Gracias. Ese error necesita un mejor mensaje. Cuando mencionó las restricciones de verificación en la tabla (cuando no había restricción de verificación), no se me ocurrió que la falta de una restricción de verificación era, de hecho, el problema.
Colin Daley

Respuestas:

11

Cuando trabaje con el cambio de partición, SQL Server deberá verificar que los límites de la tabla / partición de origen puedan caber en los límites de la tabla / partición de destino. En otras palabras, usted está tratando de datos de conmutación de dbo.temp_tablea dbo.play_table's partición 2. Piense en ello como esto, los datos para el c1en dbo.temp_tableestá limitada sólo por el tipo de datos ( int), lo que puede tener valores comprendidos entre -2147483648 a 2147483647 . Pero a la inversa, su destino ( dbo.play_tablepartición 2) tiene un rango de 4 a 2,147,483,647.

Sus datos no violan esto, pero son los metadatos los que no pueden permitirlo. Podría insertar fácilmente el valor -10 en dbo.temp_table. El cambio de partición fallaría de la misma manera y tendría más sentido, ya que -10 no cabe en dbo.play_tablelos límites de la segunda partición.

Si desea hacer que este código funcione, deberá decirle explícitamente a SQL Server que dbo.temp_tablenunca tendrá datos que no quepan en dbo.play_tablela segunda partición. Puede hacer esto con una restricción de verificación:

/******************************************************************************
    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
******************************************************************************/

La adición de muestra anterior a su código hace que esta sea una solución funcional. Ahora SQL Server sabe que los datos dbo.temp_tablepueden caber en la partición 2 dbo.play_tabledebido a la restricción de verificación agregada a dbo.temp_table.

Thomas Stringer
fuente