ALTER TABLE ... SWITCHing dari tabel biasa ke tabel dipartisi gagal

9

Kode di bawah ini melakukan yang berikut:

  1. Membuat database play_partition di C: \ TEMP
  2. Membuat dua tabel yang dipartisi identik play_table dan archive_play_table
  3. Beralih partisi play_table 1 ke archive_play_table partisi 1
  4. Membuat tabel tanpa partisi baru temp_table dengan struktur yang sama seperti play_table pada filegroup yang sama dengan partisi play_table 2
  5. Alihkan play_table_partition 2 ke temp_table
  6. Mencoba untuk beralih temp_table kembali ke partisi play_table 2 dan gagal dengan

    Msg 4982, Level 16, Status 1, Baris 64 ALTER TABLE SWITCH pernyataan gagal. Periksa batasan tabel sumber 'play_partition.dbo.temp_table' memungkinkan nilai yang tidak diizinkan oleh kisaran yang ditentukan oleh partisi 2 pada tabel target 'play_partition.dbo.play_table'.

Mengapa ini gagal?

Saya menggunakan SQL Server 2014 (Percobaan Edisi Perusahaan).

Salam,

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
sumber
Memberi +1 pada pertanyaan Anda. Anda membuatnya mudah untuk menjawab dan menjawab, karena DDL Anda taruh di sini. Untuk itu, terima kasih. Saya berharap saya bisa +10 pertanyaan seperti ini.
Thomas Stringer
Terima kasih. Kesalahan itu membutuhkan pesan yang lebih baik. Ketika disebutkan periksa kendala di atas meja (ketika tidak ada kendala periksa), tidak terpikir oleh saya bahwa kurangnya kendala pemeriksaan adalah, pada kenyataannya, masalah.
Colin Daley

Jawaban:

11

Ketika Anda bekerja dengan peralihan partisi, SQL Server perlu memverifikasi bahwa tabel sumber / batas partisi dapat masuk dalam tabel tujuan / batas partisi. Dengan kata lain, Anda mencoba untuk mengalihkan data dari dbo.temp_tableke dbo.play_tablepartisi 2. Pikirkan seperti ini, data untuk c1in dbo.temp_tablehanya dibatasi oleh tipe data ( int), sehingga Anda dapat memiliki nilai mulai dari -2,147,483,648 hingga 2,147,483,647 . Tetapi sebaliknya, tujuan Anda ( dbo.play_tablepartisi 2) berkisar antara 4 hingga 2.147.483.647.

Data Anda tidak melanggar ini, tetapi metadata yang tidak memungkinkan ini. Anda bisa dengan mudah memasukkan nilai -10 ke dalam dbo.temp_table. Pergantian partisi akan gagal dengan cara yang sama dan lebih masuk akal, karena -10 tidak cocok dengan dbo.play_tablebatas-batas partisi ke-2.

Jika Anda ingin membuat kode ini berfungsi, Anda harus secara eksplisit memberi tahu SQL Server bahwa dbo.temp_tabletidak akan pernah ada data yang tidak sesuai dengan dbo.play_tablepartisi ke-2. Anda bisa melakukan ini dengan batasan cek:

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

Itu penambahan sampel di atas untuk kode Anda membuat ini solusi yang berfungsi. Sekarang SQL Server tahu bahwa data di dbo.temp_tabledapat masuk dalam partisi 2 dbo.play_tablekarena kendala cek yang ditambahkan dbo.temp_table.

Thomas Stringer
sumber