Click here to monitor SSC
SQLServerCentral is supported by Red Gate Software Ltd.
 
Log in  ::  Register  ::  Not logged in
 
 
 

Getting Rid of Excessive Files and Filegroups in SQL Server

By Chad Miller,

Getting rid of excess files and filegroups:

Getting Rid of Excessive Files and Filegroups in SQL Server 7.0/2000

 

Recently I began supporting a database with 16 filegroups, which in and of itself is not issue.  However this particular database is only 7 GB in total used size and all of the 16 files are were located on a single EMC symmetrix volume.  Because of the use of file groups the database had expanded to a total of 15 GB unnecessarily doubling its size.  Although there are legitimate reasons to use filegroups; In this situation 16 file groups were clearly excessive and did not create substantial value since all of the files were located on a single volume.  Although it could be argued that filegroups can aid in recovering certain tables without restoring the entire database, this type of recoverability was not needed.  If you buy quality physical disks and back/recovery software you can avoid using filegroups entirely.  So, I set out to remove 15 filegroups in favor of a single PRIMARY filegroup.

 

I wanted to remove files/filegroups by using scripts, so began by creating scripts to move all objects to the PRIMARY filegroup:

 

I began by backing up and restoring the existing production database to a QA environment, setting the recovery mode to simple, setting the default filegroup to primary and expanding the primary filegroup large enough to hold all database objects and accommodate index rebuilds/future growth:

 

 

ALTER DATABASE MyDB

SET RECOVERY SIMPLE

GO

ALTER DATABASE MyDB

MODIFY FILEGROUP [PRIMARY] DEFAULT

GO

ALTER DATABASE MyDB

MODIFY FILE

   (NAME = MYDB_fg_primary,

   SIZE = 10000MB,

   MAXSIZE = 20000MB,

   FILEGROWTH=500MB)

GO

 

Once this had been accomplished I scripted out all clustered indexes and noclustered indexes for those table with clustered indexes and then rebuilt those indexes on the PRIMARY filegroup.  Tables without a clustered index or without any indexes must be handled differently.

 

Drop the non-clustered indexes of tables with clustered indexes

 

DROP INDEX TblWithClustIDX.IX_NonClustCol

 

 Drop the clustered index, which in this case is also the primary key constraint.

 

ALTER TABLE TblWithClustIDX DROP CONSTRAINT PK_TblWithClustIDX

GO

 

Once the non-clustered and clustered indexes have been dropped rebuild the clustered and non-clustered indexes on the PRIMARY filegroup:

 

ALTER TABLE TblWithClustIDX

    ADD     CONSTRAINT PK_TblWithClustIDX

    PRIMARY KEY CLUSTERED (ClustCol) 

ON [PRIMARY]

GO

 

CREATE NONCLUSTERED INDEX IX_ NonClustCol

    ON TblWithClustIDX(NonClustCol)

 

    ON [PRIMARY]

GO

 

For tables without a clustered index, but with a nonclustered index you can move the data pages to the primary filegroup by dropping the existing non-clustered index and recreating the index as clustered.  Then you can return the index to it’s original, nonclustered state by dropping and recreating again on the PRIMARY filegroup:

 

For example, TblWithClustIDXOnly does not have a clustered index, only nonclustered indexes.

 

 Drop existing nonclustered index, which in this case is a primary key.

 

CREATE UNIQUE CLUSTERED

  INDEX PK_TblWithClustIDXOnly ON dbo.TblWithClustIDXOnly (NonClustCol)

WITH

    DROP_EXISTING

ON PRIMARY

GO

 

Drop the clustered index you’ve just created.

 

ALTER TABLE TblWithClustIDXOnly DROP CONSTRAINT PK_TblWithClustIDXOnly

GO

 

Recreate the nonclustered index on the primary filegroup.

 

ALTER TABLE TblWithClustIDXOnly

    ADD     CONSTRAINT PK_TblWithClustIDXOnly

    PRIMARY KEY NONCLUSTERED (NonClustCol)

ON PRIMARY

GO

 

For tables without indexes you can simply move their data pages to the primary filegroup by selecting them into another database, dropping the existing table from the original and then selecting the table back into the original database.

 

SELECT * INTO DBObjCopy.dbo.NoIndexesTable FROM NoIndexesTable

GO

DROP TABLE NoIndexesTable

GO

SELECT * INTO dbo.NoIndexesTable FROM DBObjCopy.dbo.NoIndexesTable

GO

 

At this point I thought I was done and could safely drop the files. However when I attempted to drop several of the filegroups SQL Server returned an error message indicating the file could not be dropped because it was not empty (SQL Server will not let you drop a file or filegroup if it is not empty).  So I set out to determine which objects were still located on a filegroup other than the primary group.  The undocumented stored procedure sp_objectfilegroup will list the filegroup for an object provided you pass it the object_id, but I did not know the object_id plus I wanted to run an object to filegroup query for all objects.  Using sp_objectfilegroup as a starting point and building on the query used by sp_objectfilegroup; I came up with a query to show all of the table/object names that are located on a filegroup other than primary:

 

--Listing 1:  T-SQL to Display objects and filegroups not on Primary Filegroup

select TableNAME = o.name, ObjectName = i.name, i.indid, s.groupname

                  from sysfilegroups s, sysindexes i, sysobjects o

                  where i.id = o.id

                        and o.type in ('S ','U ') --system or user table

                        and i.groupid = s.groupid

AND s.groupname <> 'PRIMARY'

 

--indid values

-- 1 clustered index

-- 0 heap

-- 255 text/image

-- > 1 nonclustered index or statistic

 

After I running the query I could see I had several hundred objects still located on the various filegroups.  Since I’d taken care of the clustered indexes and the heaps (both with and without nonclustered indexes), the indid and name indicated the remaining objects were of two types:  text/image columns and statistics.   All but a few of them were system-generated statistics and the rest were text/image columns.  SQL Server had created hundreds of system-generated statistics (all are named an _WA%), which appeared to be located on the same filegroup as the table’s original filegroup.

 

I could simply drop all the system-generated statistics, however I didn’t want to take the performance hit of re-generating these statistics during production hours.  So I created another script to drop all of the statistics and re-create them.  When they were recreated they were then located on the primary filegroup.

 

 

Listing 2: T-SQL to Drop and recreate all statisitics

SET NOCOUNT ON

GO

 

create table #stat

(stat_name sysname,

stat_keys varchar(1000),

table_name varchar(100))

Go

 

DECLARE tab CURSOR

READ_ONLY

FOR SELECT table_name FROM information_schema.tables

 

DECLARE @name varchar(40)

OPEN tab

 

FETCH NEXT FROM tab INTO @name

WHILE (@@fetch_status <> -1)

BEGIN

      IF (@@fetch_status <> -2)

      BEGIN

            insert into #stat(stat_name,stat_keys)

            EXEC sp_helpstats @name

            update #stat

            set table_name = @name

            where table_name is null

      END

      FETCH NEXT FROM tab INTO @name

END

 

CLOSE tab

DEALLOCATE tab

GO

 

PRINT 'PRINT ''<<< DROPPING STATISTICS >>>'''

GO

 select 'DROP STATISTICS ' + TABLE_NAME + '.' + STAT_NAME + '

 ' + 'GO' from #stat

GO

PRINT 'PRINT ''<<< DROP STATISTICS COMPLETE >>>'''

GO

PRINT 'PRINT ''<<< CREATING STATISTICS >>>'''

GO

 select 'CREATE STATISTICS ' + STAT_NAME + '

 ' + 'ON MyDB..' + TABLE_NAME + '(' + STAT_KEYS + ')' + '

 ' + 'GO' from #stat

GO

PRINT 'PRINT ''<<< CREATE STATISTICS COMPLETE >>>'''

GO

 

Once statistics were moved to the primary filegroup, all I had left to do was move the text/image columns.  For this and only this portion I chose to use Enterprise Manager.  Using the filegroup query in Listing 1, I identified 8 tables with text/image columns not located on the primary filegroup.  To use EM to move text/image columns to a new filegroup go to Design Table >> Properties and select the new filegroup from the Text Filegroup drop down list.

 

Since I had moved all tables, indexes and statistics to the primary filegroup by using scripts—I thought it would be nice to do the same with the text/image columns. Using profiler I traced the process of using Enterprise Manager to change text/image column filegroup.  Unfortunately I discovered that SQL Server would drop and recreate the table in order to move the text/image column to primary filegroup.  Although I could have accomplished moving to a new filegroup by backing up the table via  “select into…” and dropping and recreating I felt it would be easier to just let Enterprise Manager do this and since it was only 8 tables I didn’t mind manually changing these columns via Enterprise Manager.

 

Once the text/image columns had been moved I ran the query in Listing 1 and finally, there were no objects located on any filegroup other than the primary filegroup.  Once again I attempted to drop the files and SQL Server again returned an error message indicating the files were not empty.  I then shrank the files using DBCC SHRINKFILE and was finally able to the drop the files and filegroups.

 

Mission accomplished!  You’re probably wondering if this all was worth it?  Yes, I could have used Enterprise Manager entirely instead of scripts, however going through 170 tables manually changing filegroups did not appeal to me. Also because of production refreshes of QA, ongoing testing of filegroup moves and production implementation I would have to go through this whole process at least a half dozen more times.  So, it did save me time.  I would rather use testable, repeatable scripts to move changes into production instead of error prone labor-intensive processes utilizing Enterprise Manager.

Total article views: 11824 | Views in the last 30 days: 9
 
Related Articles
FORUM

Primary key without cluster index

can i create primary key on table without cluster index?

FORUM

Creating a Primary Key over an existing Unique, Clustered Index

Primary Key, Clustered Index, Modification

FORUM

Primary Filegroup

Puzzled by Primary Filegroup size

FORUM

clustered index

clustered index

FORUM

Service Broker indexes on non primary filegroup

Need to remove filegroup but it has service broker indexes

Tags
administration    
configuring    
sql server 7    
 
Contribute

Join the most active online SQL Server Community

SQL knowledge, delivered daily, free:

Email address:  

You make SSC a better place

As a member of SQLServerCentral, you get free access to loads of fresh content: thousands of articles and SQL scripts, a library of free eBooks, a weekly database news roundup, a great Q & A platform… And it’s our huge, buzzing community of SQL Server Professionals that makes it such a success.

Join us!

Steve Jones
Editor, SQLServerCentral.com

Already a member? Jump in:

Email address:   Password:   Remember me: Forgotten your password?
Steve Jones