Click here to monitor SSC
SQLServerCentral is supported by Red Gate Software Ltd.
 
Log in  ::  Register  ::  Not logged in
 
 
 
        
Home       Members    Calendar    Who's On


Add to briefcase

partitioning - swapping in from smaller higher grain to lower grain Expand / Collapse
Author
Message
Posted Sunday, January 27, 2013 3:12 AM
SSC Eights!

SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!

Group: General Forum Members
Last Login: Wednesday, August 20, 2014 4:12 AM
Points: 897, Visits: 1,852
I have a table partitioned at the grain of Year.
I have a second table partitioned at the grain of month.

I could swap a partition from the table at the year grain (partition 3) to the table at the month grain (into partition 7) , but i cannot swap it back.
I get this error:

ALTER TABLE SWITCH statement failed. Range defined by partition 7 in table 'PartitionTest.dbo.swapouttable' is not a subset of range defined by partition 3 in table 'PartitionTest.dbo.orderdetail'.


I can post code to reproduce, but off hand, anyone know why i cannot swap back from the month table into the year table? Is it a one way trip without some extra steps?

EDIT: Below is a cheap n nasty script to repro the issue. NOTE - Im using sample data from Adventureworks2012

--create database
CREATE DATABASE PartitionTests
on Primary
(name = primary_data, filename = 'C:\SQLServerFiles\Partitioning\Files\db_1.mdf', size= 5MB, Filegrowth=500kb, MAXSIZE = 10MB),
FILEGROUP FG1
(NAME = FG1Data, filename = 'C:\SQLServerFiles\Partitioning\Files\FG_1.mdf', size= 500KB, Filegrowth=500kb, MAXSIZE = 10MB),
FILEGROUP FG2
(name = FG2Data, filename = 'C:\SQLServerFiles\Partitioning\Files\FG_2.mdf', size= 500KB, Filegrowth=500kb, MAXSIZE = 10MB)
LOG ON
(NAME = DB_LOG, filename = 'C:\SQLServerFiles\Partitioning\Files\log_1.ldf', size = 1MB, Filegrowth=500kb, MAXSIZE=5MB)



use partitiontests

--get sample data (used Adventureworks2012)]

select * into OrderDetail
from adventureworks2012.Purchasing.PurchaseOrderDetail


--create yearly partition function & scheme

create partition function YearlyPartitionFunction(datetime)
AS RANGE LEFT
FOR VALUES('2005-01-01','2006-01-01','2007-01-01','2008-01-01',
'2009-01-01', '2010-01-01')

CREATE PARTITION SCHEME YearlyPartitionScheme
AS PARTITION YearlyPartitionFunction TO
(FG2,FG2,FG2,FG2,FG2,FG2,FG2)


--create monthly partition and scheme

create partition function monthlyPartitionFunction(datetime)
AS RANGE LEFT
FOR VALUES('2005-05-01','2005-06-01','2005-07-01','2005-08-01',
'2005-09-01', '2005-10-01')

CREATE PARTITION SCHEME MonthlyPartitionScheme
AS PARTITION monthlyPartitionFunction TO
(FG2,FG2,FG2,FG2,FG2,FG2,FG2)


--partition source table

CREATE CLUSTERED INDEX ix_pk_pt on OrderDetail(PurchaseOrderID) on YearlyPartitionScheme(modifieddate)

--create swapout table

CREATE TABLE [dbo].[swapouttable](
[PurchaseOrderID] [int] NOT NULL,
[PurchaseOrderDetailID] [int] IDENTITY(1,1) NOT NULL,
[DueDate] [datetime] NOT NULL,
[OrderQty] [smallint] NOT NULL,
[ProductID] [int] NOT NULL,
[UnitPrice] [money] NOT NULL,
[LineTotal] [money] NOT NULL,
[ReceivedQty] [decimal](8, 2) NOT NULL,
[RejectedQty] [decimal](8, 2) NOT NULL,
[StockedQty] [decimal](9, 2) NOT NULL,
[ModifiedDate] [datetime] NOT NULL
)

--create clust index on swapout table to match that of source table

CREATE CLUSTERED INDEX ix_pk_pt2 on swapouttable(PurchaseOrderID)
on monthlyPartitionScheme(modifieddate)


--swapout rows - no problem
alter table orderdetail
switch partition 3 to swapoutTable Partition 7


--swap rows back - ERROR
alter table swapoutTable
switch partition 7 to orderdetail Partition 3
/*
ALTER TABLE SWITCH statement failed. Range defined by partition 7 in table 'PartitionTests.dbo.swapoutTable'
is not a subset of range defined by partition 3 in table 'PartitionTests.dbo.orderdetail'.
*/

Post #1412113
Posted Sunday, January 27, 2013 8:28 AM


SSCertifiable

SSCertifiableSSCertifiableSSCertifiableSSCertifiableSSCertifiableSSCertifiableSSCertifiableSSCertifiableSSCertifiable

Group: General Forum Members
Last Login: Yesterday @ 6:36 PM
Points: 7,097, Visits: 12,600
Even though you have different partition functions you can swap the partition out because the structure is the same and the partition boundary in the source is a subset of the boundary in the destination. Running this query (credit to Dan Guzman) we can see the boundaries of each partition:

--paritioned table and index details
SELECT OBJECT_NAME(p.object_id) AS ObjectName,
i.name AS IndexName,
p.index_id AS IndexID,
ds.name AS PartitionScheme,
p.partition_number AS PartitionNumber,
fg.name AS FileGroupName,
prv_left.value AS LowerBoundaryValue,
prv_right.value AS UpperBoundaryValue,
CASE pf.boundary_value_on_right
WHEN 1 THEN 'RIGHT'
ELSE 'LEFT'
END AS Range,
p.rows AS Rows
FROM sys.partitions AS p
JOIN sys.indexes AS i ON i.object_id = p.object_id
AND i.index_id = p.index_id
JOIN sys.data_spaces AS ds ON ds.data_space_id = i.data_space_id
JOIN sys.partition_schemes AS ps ON ps.data_space_id = ds.data_space_id
JOIN sys.partition_functions AS pf ON pf.function_id = ps.function_id
JOIN sys.destination_data_spaces AS dds2 ON dds2.partition_scheme_id = ps.data_space_id
AND dds2.destination_id = p.partition_number
JOIN sys.filegroups AS fg ON fg.data_space_id = dds2.data_space_id
LEFT JOIN sys.partition_range_values AS prv_left ON ps.function_id = prv_left.function_id
AND prv_left.boundary_id = p.partition_number - 1
LEFT JOIN sys.partition_range_values AS prv_right ON ps.function_id = prv_right.function_id
AND prv_right.boundary_id = p.partition_number
WHERE OBJECTPROPERTY(p.object_id, 'ISMSShipped') = 0
UNION ALL
--non-partitioned table/indexes
SELECT OBJECT_NAME(p.object_id) AS ObjectName,
i.name AS IndexName,
p.index_id AS IndexID,
NULL AS PartitionScheme,
p.partition_number AS PartitionNumber,
fg.name AS FileGroupName,
NULL AS LowerBoundaryValue,
NULL AS UpperBoundaryValue,
NULL AS Boundary,
p.rows AS Rows
FROM sys.partitions AS p
JOIN sys.indexes AS i ON i.object_id = p.object_id
AND i.index_id = p.index_id
JOIN sys.data_spaces AS ds ON ds.data_space_id = i.data_space_id
JOIN sys.filegroups AS fg ON fg.data_space_id = i.data_space_id
WHERE OBJECTPROPERTY(p.object_id, 'ISMSShipped') = 0
ORDER BY ObjectName,
IndexID,
PartitionNumber;

Notice that the source is a subset of the destination but the converse is not true. Since the partition swap is a DDL operation no data is evaluated to see if the data actually could conform to the boundary, it just says yes or no based on the metadata.



__________________________________________________________________________________________________
There are no special teachers of virtue, because virtue is taught by the whole community. --Plato


  Post Attachments 
partbounds.jpg (69 views, 157.06 KB)
Post #1412130
Posted Monday, January 28, 2013 3:09 AM
Grasshopper

GrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopperGrasshopper

Group: General Forum Members
Last Login: Tuesday, September 10, 2013 6:49 AM
Points: 21, Visits: 26
invalid post
Post #1412289
Posted Monday, January 28, 2013 4:08 AM
SSC Eights!

SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!

Group: General Forum Members
Last Login: Wednesday, August 20, 2014 4:12 AM
Points: 897, Visits: 1,852
issue resolved with a constraint on the date column. seems the engine is happy to do the swap if the constraint enforces only rows that can only go into the destination partition.
Post #1412328
Posted Monday, January 28, 2013 7:07 AM


SSCertifiable

SSCertifiableSSCertifiableSSCertifiableSSCertifiableSSCertifiableSSCertifiableSSCertifiableSSCertifiableSSCertifiable

Group: General Forum Members
Last Login: Yesterday @ 6:36 PM
Points: 7,097, Visits: 12,600
winston Smith (1/28/2013)
issue resolved with a constraint on the date column. seems the engine is happy to do the swap if the constraint enforces only rows that can only go into the destination partition.

That makes perfect sense since the swap must be carried out as purely a DDL operation and the check constraint can help the engine know the data in the partition subscribes to the destination partition boundaries without actually looking at the data during the switch.

For future onlookers it's worth expounding on the point of adding a check constraint. The constraint must be added WITH CHECK after the partition is switched into the swapouttable, i.e. having the check constraint in place before the switch is not good enough since the switch into that table is purely a DDL operation and so the data is not checked. This leaves the check constraint in a not trusted status per sys.check_constraints. Even when adding the constraint WITH NOCHECK before the switch and then CHECKing it after the swap the trusted status still cannot be attained.

@winston, just curious, why not simply define the swapouttable CI using the same partition scheme as the OrderDetail CI?


__________________________________________________________________________________________________
There are no special teachers of virtue, because virtue is taught by the whole community. --Plato
Post #1412415
Posted Monday, January 28, 2013 8:56 AM
SSC Eights!

SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!SSC Eights!

Group: General Forum Members
Last Login: Wednesday, August 20, 2014 4:12 AM
Points: 897, Visits: 1,852
My ideal choice is simplification, but we have a client who asked we investigate a bit of an over complex solution and this is one issue that cropped up.

Thanks for the help!
Post #1412483
« Prev Topic | Next Topic »

Add to briefcase

Permissions Expand / Collapse