Sunday, December 5, 2010

Script to find the size of the user tables in a database

Listed below is the script to find the size of user tables in a database. Script creates a stored procedure named "usp_AllUserTableSizes" in the master database . Execute the proc to see the result.

-- Set Settings ON
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

-- ===================================================================
-- Script Code : TDD1
-- Create date : 12/05/2010
-- Description : User tables sizes are displayed
-- ===================================================================

-- Drop Store Procedure if Exist
IF OBJECT_ID ( 'dbo.usp_AllUserTableSizes', 'P' ) IS NOT NULL
    DROP PROCEDURE usp_AllUserTableSizes
GO

-- Create or Alter Procedure
CREATE PROCEDURE usp_AllUserTableSizes

-- Add the parameters for the stored procedure here

AS
-- Declaration Section --------------------------------------------------------------------------------------------------------
DECLARE @id           int                
DECLARE @type           char(2)          
DECLARE     @pages            int              
DECLARE @dbname       sysname
DECLARE @dbsize       dec(15,0)
DECLARE @bytesperpage dec(15,0)
DECLARE @pagesperMB       dec(15,0)

create table #spt_space
(
      objid       int null,
      rows        int null,
      reserved    dec(15) null,
      data        dec(15) null,
      indexp            dec(15) null,
      unused            dec(15) null
)
-- Set variable values here -------------------------------------------------------------------
set nocount on
-- Create a cursor to loop through the user tables
declare c_tables cursor for
select      id
from  sysobjects
where xtype = 'U'

open c_tables

fetch next from c_tables
into @id

while @@fetch_status = 0
begin

      /* Code from sp_spaceused */
      insert into #spt_space (objid, reserved)
            select objid = @id, sum(reserved)
                  from sysindexes
                        where indid in (0, 1, 255)
                              and id = @id

      select @pages = sum(dpages)
                  from sysindexes
                        where indid < 2
                              and id = @id
      select @pages = @pages + isnull(sum(used), 0)
            from sysindexes
                  where indid = 255
                        and id = @id
      update #spt_space
            set data = @pages
      where objid = @id


      /* index: sum(used) where indid in (0, 1, 255) - data */
      update #spt_space
            set indexp = (select sum(used)
                        from sysindexes
                        where indid in (0, 1, 255)
                        and id = @id)
                      - data
            where objid = @id

      /* unused: sum(reserved) - sum(used) where indid in (0, 1, 255) */
      update #spt_space
            set unused = reserved
                        - (select sum(used)
                              from sysindexes
                                    where indid in (0, 1, 255)
                                    and id = @id)
            where objid = @id

      update #spt_space
            set rows = i.rows
                  from sysindexes i
                        where i.indid < 2
                        and i.id = @id
                        and objid = @id

      fetch next from c_tables
      into @id
end

select      TableName = (select left(name,60) from sysobjects where id = objid),
      Rows = convert(char(11), rows),
      ReservedKB = ltrim(str(reserved * d.low / 1024.,15,0) + ' ' + 'KB'),
      ReservedMB = ltrim(str(reserved * d.low / 1024 / 1024.,15,0) + ' ' + 'MB'),
      ReservedGB = ltrim(str(reserved * d.low / 1024/ 1024 / 1024.,15,0) + ' ' + 'GB'),
      DataKB = ltrim(str(data * d.low / 1024.,15,0) + ' ' + 'KB'),
      DataMB = ltrim(str(data * d.low / 1024 / 1024.,15,0) + ' ' + 'MB'),
      DataGB = ltrim(str(data * d.low / 1024 / 1024 /1024.,15,0) + ' ' + 'GB'),
      IndexSizeKB = ltrim(str(indexp * d.low / 1024.,15,0) + ' ' + 'KB'),
      UnusedKB = ltrim(str(unused * d.low / 1024.,15,0) + ' ' + 'KB')
           
from #spt_space, master.dbo.spt_values d
where       d.number = 1
and   d.type = 'E'
order by reserved desc
drop table #spt_space
close c_tables
deallocate c_tables













Saturday, November 27, 2010

Tempdb Drastic Growth – An Analysis


Space Usage By A Tempdb shoots up drastically  in a production environment”
 
   This is quite a common  scenario in a DBA activity.A simple and clear explanation of the basics behind temdb is explained here.

Tempdb is designed to hold database related dynamic objects in it. When under execution these objects stay put in tempdb.

Tempdb is mainly used for extending memory to the sort operations, and session specific temporary objects.

How doest it grow?

Tempdb is a shell which gets expanded as per memory need, once it gets expanded it never shrinks back even though the usage is minimal than the size.So the actual size of the .mdf file that you see using

“sp_helpdb tempdb”

WILL NOT give the actual usage . To get the actual usage of the tempdb the following script can be used,

*************************************************************

Use tempdb

SELECT

a.FILEID,

CONVERT(decimal(12,2),ROUND(a.size/128.000,2)) as [FILESIZEINMB] ,

CONVERT(decimal(12,2),ROUND(fileproperty(a.name,'SpaceUsed')/128.000,2)) as
[SPACEUSEDINMB],

CONVERT(decimal(12,2),ROUND((a.size-fileproperty(a.name,'SpaceUsed'))/128.000,2))
 as [FREESPACEINMB],

a.name as [DATAFILENAME],

a.FILENAME as [FILENAME]

FROM dbo.sysfiles a

ORDER BY fileid


*************************************************************

Workaround:

If the temp db drive is filling up fast , the only option is to restart the service which will reset the size of it. But this option is quite a bold one considering the criticality of the server.

DBCC OPENTRAN() can be executed to see the long running threads in the server, killing them may release huge workloads on tempdb. Even this decision holds the value of the thread being executed.

Fix:      
Tempdb growth can be limited by the following steps:
  1. Less critical db can be set in simple recovery mode
  2. Huge sort operation can be done by placing the databases in SIMPLE recovery mode , where they can be changed back to FULL once the activity is completed.
  3. Adding more .mdf files is an option for load balancing of the tempdb.
  4. Capacity planning for server should be perfect  with regards to tempdb