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.