ALTER TABLE ... COMMUTAZIONE dalla tabella normale alla tabella partizionata non riesce


9

Il codice seguente effettua le seguenti operazioni:

  1. Crea una partizione play_ database in C: \ TEMP
  2. Crea due tabelle partizionate identiche play_table e archive_play_table
  3. Passa la partizione 1 di play_table alla partizione 1 di archive_play_table
  4. Crea una nuova tabella non partizionata temp_table con la stessa struttura di play_table sullo stesso filegroup della partizione play_table 2
  5. Passa play_table_partition 2 a temp_table
  6. Cerca di riportare temp_table alla partizione play_table 2 e fallisce

    Messaggio 4982, livello 16, stato 1, riga 64 Istruzione ALTER TABLE SWITCH non riuscita. Controllare i vincoli della tabella di origine 'play_partition.dbo.temp_table' consentire valori non consentiti dall'intervallo definito dalla partizione 2 sulla tabella di destinazione 'play_partition.dbo.play_table'.

Perché fallisce?

Sto usando SQL Server 2014 (Enterprise Edition Trial).

Saluti,

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 sulla tua domanda. Hai semplificato la riproduzione e la risposta, grazie al DDL che hai inserito qui. Per quello, grazie. Vorrei poter +10 domande come questa.
Thomas Stringer,

Grazie. Quell'errore ha bisogno di un messaggio migliore. Quando menzionava i vincoli di controllo sulla tabella (quando non c'erano vincoli di controllo), non mi venne in mente che la mancanza di un vincolo di controllo fosse, in effetti, il problema.
Colin Daley,

Risposte:


11

Quando si lavora con il cambio di partizione, SQL Server dovrà verificare che i limiti della tabella / partizione di origine possano adattarsi ai limiti della tabella / partizione di destinazione. In altre parole, si sta cercando di dati di interruttore da dbo.temp_tablea dbo.play_table's partizione 2. Pensate a come questo, i dati per il c1di dbo.temp_tableè vincolato solo dal tipo di dati ( int), in modo da avere valori che vanno da -2.147.483.648 a 2,147,483,647 . Al contrario, la destinazione ( dbo.play_tablepartizione 2) ha un intervallo compreso tra 4 e 2.147.483.647.

I tuoi dati non violano questo, ma sono i metadati che non possono permetterlo. È possibile inserire altrettanto facilmente il valore -10 in dbo.temp_table. La commutazione della partizione fallirebbe allo stesso modo e avrebbe più senso, poiché -10 non rientra nei dbo.play_tableconfini della seconda partizione.

Se si desidera far funzionare questo codice, è necessario indicare esplicitamente a SQL Server che dbo.temp_tablenon saranno mai presenti dati che non rientrano nella dbo.play_tableseconda partizione. Puoi farlo con un vincolo di controllo:

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

Quella sopra aggiunta al tuo codice rende questa soluzione funzionante. Ora SQL Server sa che i dati dbo.temp_tablepossono rientrare nella partizione 2 di a dbo.play_tablecausa del vincolo di controllo aggiunto a dbo.temp_table.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.