ALTER TABLE… Das Umschalten von der regulären Tabelle zur partitionierten Tabelle schlägt fehl

9

Der folgende Code bewirkt Folgendes:

  1. Erstellt eine Datenbank play_partition in C: \ TEMP
  2. Erstellt zwei identische partitionierte Tabellen play_table und archive_play_table
  3. Schaltet die play_table-Partition 1 auf die archive_play_table-Partition 1 um
  4. Erstellt eine neue nicht partitionierte Tabelle temp_table mit derselben Struktur wie play_table in derselben Dateigruppe wie play_table Partition 2
  5. Schaltet play_table_partition 2 auf temp_table um
  6. Versucht, temp_table wieder auf play_table Partition 2 umzuschalten und schlägt mit fehl

    Meldung 4982, Ebene 16, Status 1, Zeile 64 ALTER TABLE SWITCH-Anweisung fehlgeschlagen. Überprüfen Sie die Einschränkungen der Quelltabelle 'play_partition.dbo.temp_table' und lassen Sie Werte zu, die nach dem von Partition 2 in der Zieltabelle 'play_partition.dbo.play_table' definierten Bereich nicht zulässig sind.

Warum scheitert es?

Ich verwende SQL Server 2014 (Enterprise Edition-Testversion).

Grüße,

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
quelle
+1 auf deine Frage. Sie haben es einfach gemacht, Repro und Antwort zu geben, dank DDL, das Sie hier eingegeben haben. Dafür danke. Ich wünschte, ich könnte +10 Fragen wie diese stellen.
Thomas Stringer
Vielen Dank. Dieser Fehler benötigt eine bessere Nachricht. Als in der Tabelle Prüfbeschränkungen erwähnt wurden (wenn es keine Prüfbeschränkung gab), kam mir nicht der Gedanke, dass das Fehlen einer Prüfbeschränkung tatsächlich das Problem war.
Colin Daley

Antworten:

11

Wenn Sie mit Partitionswechsel arbeiten, muss SQL Server überprüfen, ob die Grenzen der Quelltabelle / Partition in die Grenzen der Zieltabelle / Partition passen. Mit anderen Worten, Sie versuchen, Daten von dbo.temp_tableder dbo.play_tablePartition 2 zu wechseln. Stellen Sie sich das so vor: Die Daten für das c1In werden dbo.temp_tablenur durch den Datentyp ( int) eingeschränkt, sodass Sie Werte zwischen -2.147.483.648 und 2.147.483.647 haben können . Umgekehrt hat Ihr Ziel ( dbo.play_tablePartition 2) einen Bereich von 4 bis 2.147.483.647.

Ihre Daten verletzen dies nicht, aber es sind die Metadaten, die dies nicht zulassen. Sie können genauso gut den Wert -10 in einfügen dbo.temp_table. Die Partitionsumschaltung würde auf die gleiche Weise fehlschlagen und sinnvoller sein, da -10 nicht in dbo.play_tabledie 2. Partitionsgrenzen passt .

Wenn Sie diesen Code zum Laufen bringen möchten, müssen Sie SQL Server explizit mitteilen, dass dbo.temp_tableniemals Daten vorhanden sind, die nicht in dbo.play_tabledie zweite Partition passen . Sie können dies mit einer Prüfbedingung tun:

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

Die obige Beispielergänzung zu Ihrem Code macht dies zu einer funktionierenden Lösung. Jetzt weiß SQL Server, dass die Daten in dbo.temp_tablePartition 2 dbo.play_tableaufgrund der hinzugefügten Prüfbeschränkung für passen können dbo.temp_table.

Thomas Stringer
quelle