Geoff N. Hiten Blog

SQL Server thoughts, observations, and comments

Free Space Fundamentals

One of the easy ways to fail at database administration is to allow your databases to self-manage space.  Autogrow is a safety valve, not a pressure regulator.  Of course, to manage space you have to know exactly how much free space you have.  And since database objects are stored in filegroups, it would help to see free space by filegroups buth in MB and in percentages.  Well, here you go.

For those not familiar with my administration style, all my servers have an Admin database to store stuff like this. 

use Admin

go

----- Create the following table or results come back empty

--Create Table  DBSpaceUsedFileGroupExclude (

--Databasename sysname,

--FilegroupName sysname

--)

 

--------------

 

 

 

Drop procedure DBSpaceUsed

go

create procedure DBSpaceUsed as

set nocount on

Declare @DBName SysName

Declare @Cmd varchar(1000)

 

Create Table #FooTable (

      [DBName]    sysname NULL,

      [FileId]    int,

      [FileGroup] int,

      [TotalExtents]    int,

      [UsedExtents]     int,

      [DevName]   sysname,

      [FileName]  sysname,

      [FileGroupName]   Sysname NULL)

 

 

Declare DBCursor cursor READ_ONLY FORWARD_ONLY for Select [name] from master.dbo.sysdatabases

--    where [name] in ('SiteData', 'JobAppl')

-- Exclusion now based on table Admin.dbo.DBSpaceUsedFileGroupExclude.  Table contains database and filegroup

-- names that are deleted from the final table.

 

open DBCursor

Fetch next from DBCursor into @DBName

while 0 = @@Fetch_Status

      begin

      select @CMD = 'USE ' + @DBName + ' dbcc ShowFileStats with TABLERESULTS'

      insert INTO #FooTable (FileId,

      [FileGroup],

      TotalExtents,

      UsedExtents,

      DevName,

      [FileName]) exec (@cmd)

      update #FooTable set DBName = @DBName

      where DBName is null

      select @Cmd = 'USE [' + @DBName + '] Update #FooTable set [FileGroupName] = SFG.GroupName

            from #FooTable FT

            inner join sysfilegroups SFG

            on FT.[Filegroup] = SFG.[GroupID]

      where FT.[FileGroupName] IS NULL'

 

      exec (@Cmd)

      Fetch next from DBCursor into @DBName

      end

 

Close DBCursor

Deallocate DBCursor

delete from #FooTable

      from #FooTable FT

      inner join Admin.dbo.DBSpaceUsedFileGroupExclude EX

            on EX.Databasename = FT.DBName

            and EX.FileGroupName = FT.FileGroupName

 

select @@Servername as Server, DBName,         FileGroupName,

        convert(decimal (5,2), 100 - (sum(TotalExtents)-SUM(UsedExtents)) /(convert(numeric,sum(TotalExtents))) * 100) as PercentFull,

      (sum(TotalExtents)  * 64) /(1024 ) AS MBTotal,

      (sum(UsedExtents) * 64) /(1024 ) AS MBUsed,

      (sum(TotalExtents - UsedExtents) * 64) /(1024 ) AS MBFree

 

        from #FooTable FT

      group by DBName, FileGroupName

 

drop Table #FooTable