Take the 2-minute tour ×
Database Administrators Stack Exchange is a question and answer site for database professionals who wish to improve their database skills and learn from others in the community. It's 100% free, no registration required.

Historic Reporting Server running SQL 2008 R2.

I'm trying to tweak the fill factor. I have a job that records the fragmentation when the jobs runs in the early hours.

For every table that had high fragmentation I have reduced the fill factor from the 100% default for specific indexes which has worked well. But my largest 3 tables are partitioned.

Unfortunately in SQL 2008 R2 you cannot amend the fill factor on a specific partition. The fragmentation on the active partition is 99% on several of these indexes when the job runs.

I don't want to increase all partitions as they are huge, already take 150GB of 250GB db. Does anyone have any suggestions on a workaround or do I have to wait for the next major release hoping this fairly large omission in partitioned table manitenance is corrected.

share|improve this question
    
If you haven't heard of any per-partition maintenance improvements yet, I wouldn't get my hopes up they'll magically appear in Denali. This is the kind of thing they trumpet from the beginning. :-) –  Aaron Bertrand Sep 12 '11 at 16:03
add comment

1 Answer

up vote 2 down vote accepted

An option you can try is to combine partitioned views with the table level partitioning. By having a partitioned view which is current and historic tables unioned together, you will be able to have different table options i.e. fill factor etc. This also with give better statistics on the active portion of the data as it's no longer skewed with all the historic data.

USE master;
GO
DROP DATABASE PartitionDemo
GO
CREATE DATABASE PartitionDemo
GO
USE PartitionDemo;
GO
CREATE PARTITION FUNCTION everyHundredThousand(int) AS RANGE RIGHT FOR VALUES(100000,200000,300000,400000,500000,600000,700000,800000,900000,1000000)
CREATE PARTITION SCHEME allPrimary AS PARTITION everyHundredThousand ALL TO ([PRIMARY]);
GO
CREATE TABLE    dbo.HistoryTable
(
    ID  int NOT NULL /*Note not an identity*/,
    Filler char(200) NOT NULL,
    CONSTRAINT PK_HistoryTable PRIMARY KEY CLUSTERED(ID) WITH (FILLFACTOR=100) 
) ON allPrimary(ID)
GO
CREATE TABLE    dbo.CurrentTable
(
    ID  int NOT NULL IDENTITY(0,1),
    Filler char(200) NOT NULL,
    CONSTRAINT PK_CurrentTable PRIMARY KEY CLUSTERED(ID) WITH (FILLFACTOR=80) 
) ON allPrimary(ID)
GO
/* Now generate some data */
INSERT  CurrentTable
        (
            Filler
        )
SELECT      TOP 1000000
            ''
FROM        sys.objects     a
CROSS JOIN  sys.objects     b
CROSS JOIN  sys.objects     c
CROSS JOIN  sys.objects     d
GO
/* Rebuild Indexes to set Fill Factor */
ALTER INDEX ALL ON dbo.CurrentTable REBUILD
GO
/* Create Partitioned View */
CREATE VIEW CurrentPlusHistory
AS
SELECT      ID,
            Filler
FROM        HistoryTable
UNION ALL
SELECT      ID,
            Filler
FROM        CurrentTable
GO
/* Move some data to History Table */
ALTER TABLE CurrentTable SWITCH PARTITION 1 TO HistoryTable PARTITION 1
ALTER TABLE CurrentTable SWITCH PARTITION 2 TO HistoryTable PARTITION 2
ALTER TABLE CurrentTable SWITCH PARTITION 3 TO HistoryTable PARTITION 3
ALTER TABLE CurrentTable SWITCH PARTITION 4 TO HistoryTable PARTITION 4
ALTER TABLE CurrentTable SWITCH PARTITION 5 TO HistoryTable PARTITION 5
ALTER TABLE CurrentTable SWITCH PARTITION 6 TO HistoryTable PARTITION 6
ALTER TABLE CurrentTable SWITCH PARTITION 7 TO HistoryTable PARTITION 7
ALTER TABLE CurrentTable SWITCH PARTITION 8 TO HistoryTable PARTITION 8
GO
/* For the Partitioed View to work we need a check constraint to define the key range */
/* as we've not created one this query will look at both tables */
SET STATISTICS IO ON
SELECT      *
FROM        CurrentPlusHistory
WHERE       ID < 100000
AND         Filler = 'One'
SET STATISTICS IO OFF
GO
SELECT MAX(ID) FROM dbo.HistoryTable

/* Notice the range for the each table is define so SQL Server can use this value to select the target table */
ALTER TABLE dbo.HistoryTable ADD CONSTRAINT HistoryTable_ID_Range CHECK(ID<800000)
ALTER TABLE dbo.CurrentTable ADD CONSTRAINT CurrentTable_ID_Range CHECK(ID>=800000)
GO
/* Notice in the output this time SQL Server doesn't look into the current table */
SET STATISTICS IO ON
SELECT      *
FROM        CurrentPlusHistory
WHERE       ID < 100000
AND         Filler = 'One'
SET STATISTICS IO OFF
GO
/* CHECK FILLFACTORS FOR TABLES\PARTITIONS */
SELECT      OBJECT_SCHEMA_NAME(o.object_id)+'.'+o.name as Table_Name,
            s.*
FROM        sys.objects  o 
INNER JOIN  sys.dm_db_index_physical_stats(DB_ID(),NULL,NULL,NULL,'DETAILED')   s
ON          o.object_id                                 = s.object_id
AND         s.index_id                                  = 1
AND         s.index_level                               = 0
AND         s.page_count                                <>0
WHERE       o.name IN ('CurrentTable','HistoryTable')
GO
/* Now rebuild HistoryTable to see that its Partitions take the FillFactor */
ALTER INDEX ALL ON dbo.HistoryTable REBUILD
GO
/* CHECK FILLFACTORS FOR TABLES\PARTITIONS */
SELECT      OBJECT_SCHEMA_NAME(o.object_id)+'.'+o.name as Table_Name,
            s.*
FROM        sys.objects  o 
INNER JOIN  sys.dm_db_index_physical_stats(DB_ID(),NULL,NULL,NULL,'DETAILED')   s
ON          o.object_id                                 = s.object_id
AND         s.index_id                                  = 1
AND         s.index_level                               = 0
AND         s.page_count                                <>0
WHERE       o.name IN ('CurrentTable','HistoryTable')
GO
/* Move some more data into the History Table, the CHECK CONSTRAINT range has to be managed as well so this is a coding overhead */
ALTER TABLE HistoryTable DROP CONSTRAINT HistoryTable_ID_Range
ALTER TABLE HistoryTable ADD CONSTRAINT HistoryTable_ID_Range CHECK(ID<900000)
ALTER TABLE CurrentTable SWITCH PARTITION 9 TO HistoryTable PARTITION 9
ALTER TABLE CurrentTable DROP CONSTRAINT CurrentTable_ID_Range
ALTER TABLE CurrentTable ADD CONSTRAINT CurrentTable_ID_Range CHECK(ID>=900000)
GO
share|improve this answer
    
thanks for the detailed answer Martin, I will be sure to test this solution out –  DamagedGoods Sep 20 '11 at 14:35
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.