December 17, 2003 at 2:42 am
Please help me figure out why this script works everywhere except where it should.
Overview
Running a DTS Job accross multiple servers that checks database size. It's a modified sp_spaceused inside a cursor using sysdatabases. The script checks DB stats and inserts values per database into a table on another server.
Setup is:
1. DTS package create
2. Connections set to servers that need to be checked and the server containing the table for the stats.
3. ExecuteSQL Task created per target server
4. Save and Schedule package
Problem:
When running the script that reads the DB size stats in Query analyser, the select from sysdatabases used to populate the cursor works properly and values for each database on the target server are inserted into the stats table. The script also works properly when using "execute step" on a single step in DTS Designer. The script doesn't work when running multiple ExecuteSQL tasks in a DTS Package - It doesn't return db stats for some of the names that should be selected by the cursor on sysdatabases.
Script to check stats:
--declare @idint-- The object id of @objname.
--declare @typecharacter(2) -- The object type.
declare @servername varchar(20)
declare@pagesint-- Working variable for size calc.
declare @dbname sysname
declare @datapage dec(15,2)
declare @datapageMB dec(15,2)
declare @LogpageMB dec(15,2)
declare @logpage dec(15,2)
declare @unallocatedpage decimal(15,2)
declare @bytesperpagedec(15,2)
declare @pagesperMB dec(15,2)
DECLARE @DataPlusLogMB decimal(15,2)
DECLARE @Unallocated decimal(15,2)
declare @SQLstring nvarchar(4000)
-- Get the bytes per page
SELECT @bytesperpage = low
FROM master.dbo.spt_values
WHERE number = 1
AND type = 'E'
SET @pagesperMB = 1048576 / @bytesperpage
set @servername = 'Put Server Name Here'
DECLARE SpaceUsed CURSOR FOR
SELECT name
FROM master.dbo.sysdatabases
OPEN SpaceUsed
FETCH NEXT FROM SpaceUsed
INTO @DBName
WHILE @@FETCH_STATUS = 0
begin
DBCC UPDATEUSAGE (@dbname) WITH NO_INFOMSGS
-- select @datapage = sum(convert(dec(15),size))
--from @dbname.dbo.sysfiles
--where (status & 64 = 0)
Set @SQLstring = 'select @datapage = sum(convert(dec(15),size)) '
Set @SQLstring = @SQLstring + 'from ' + @dbname + '.dbo.sysfiles '
Set @SQLstring = @SQLstring + 'where (status & 64 = 0)'
Print @SQLstring
exec sp_executesql @SQLstring, N'@datapage decimal(15,0) OUTPUT', @datapage OUTPUT
--select @dbname + ' Data Device: ' + cast(@datapage as varchar(20))
Print @dbname
--select @logpage = sum(convert(dec(15),size))
--from dbo.sysfiles
--where (status & 64 <> 0)
Set @SQLString = 'select @logpage = sum(convert(dec(15),size)) '
Set @SQLString = @SQLString + 'from ' + @dbname + '.dbo.sysfiles '
Set @SQLString = @SQLString + 'where (status & 64 <> 0)'
Print @SQLstring
exec sp_executesql @SQLstring, N'@logpage decimal(15,0) OUTPUT', @logpage OUTPUT
--select @dbname + ' Log Device: ' + cast(@logpage as varchar(20))
Set @SQLString = 'SELECT @unallocatedpage = SUM(CAST(reserved AS decimal(15,0))) '
Set @SQLString = @SQLString + 'FROM '+ @dbname + '.dbo.sysindexes '
Set @SQLString = @SQLString + 'WHERE indid IN (0, 1, 255) '
Print @SQLstring
exec sp_executesql @SQLstring, N'@unallocatedpage decimal(15,0) OUTPUT', @unallocatedpage OUTPUT
--select @dbname + ' Unallocated: ' + cast(@unallocatedpage as varchar(20))
SET @DataPlusLogMB = (@datapage + @logpage) / @pagesperMB
SET @Unallocated =(@datapage - @unallocatedpage) / @pagesperMB
SET @DataPageMB = @datapage / @pagesperMB
SET @LogPageMB = @logpage / @pagesperMB
-- Change Server name Here - refer below
If not Exists (select * from ServerName.DBName.dbo.DatabaseStats
where DatabaseName like @DBName
and datediff(day, recorddate, getdate())=0)
Insert Into ServerName.DBName.dbo.DatabaseStats(ServerName,DatabaseName, UsedSpace,FreeSpace,DataDevice, LogDevice, RecordDate)
Values(@servername, @dbname, @DataPlusLogMB,@Unallocated,@DataPageMB,@LogPageMB, getdate())
FETCH NEXT FROM SpaceUsed
INTO @DBName
END
CLOSE SpaceUsed
DEALLOCATE SpaceUsed
GO
And the script to create the table for the stats
CREATE TABLE [dbo].[DatabaseStats] (
[StatsID] [int] IDENTITY (1, 1) NOT NULL ,
[ServerName] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[DatabaseName] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[UsedSpace] [decimal](18, 2) NULL ,
[FreeSpace] [decimal](18, 2) NULL ,
[DataDevice] [decimal](18, 2) NULL ,
[LogDevice] [decimal](18, 2) NULL ,
[RecordDate] [datetime] NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[DatabaseStats] WITH NOCHECK ADD
CONSTRAINT [PK_DatabaseStats] PRIMARY KEY CLUSTERED
(
[StatsID]
) ON [PRIMARY]
GO
Why, why? - it seems so simple but why doesn't it work.
G
December 17, 2003 at 3:29 am
Are there possibly any database names with invalid characters around them.... thus needing square brackets in the dynamic sql?
Not that I'm anti-cursor, but I do avoid them when I can, so I often use code such as the following if possible:
select [dbname]=db_name(), * into #sysfiles from sysfiles where 1=2
select [dbname]=db_name(), * into #sysindexes from sysindexes where 1=2
exec sp_MSforeachdb '
use -- that's a square bracket, question mark, square bracket.
dbcc updateusage (0) with no_infomsgs
insert #sysfiles select ''?'', * from sysfiles
insert #sysindexes select ''?'', * from sysindexes
'
-- then process the #sysfiles and #sysindexes tables containing info for all DBs
Cheers,
- Mark
Edited by - mccork on 12/17/2003 03:31:23 AM
Cheers,
- Mark
December 17, 2003 at 5:19 am
Thanks for response.
I understand why using sp_MSforeachdb would be a good option, So all I have to do is get all the detail out of the temp tables instead of running it per dbname in cursor?
I don't understand what this does though.
select [dbname]=db_name(), * into #sysfiles from sysfiles where 1=2
select [dbname]=db_name(), * into #sysindexes from sysindexes where 1=2
G
December 17, 2003 at 6:26 am
quote:
I don't understand what this does though.select [dbname]=db_name(), * into #sysfiles from sysfiles where 1=2
select [dbname]=db_name(), * into #sysindexes from sysindexes where 1=2
They will create temporary tables (structure only) based on the original tables.
[dbname]=db_name() is necessary to create a new column with the correct datatype.
where 1=2 is a condition that can never be true and no data will be selected.
Therefore the result will be two temporary tables based on the originals with no data (structure only).
p.s sp_MSforeachdb uses a cursor, dynamic sql and a temp table
Edited by - davidburrows on 12/17/2003 06:30:21 AM
Far away is close at hand in the images of elsewhere.
Anon.
December 17, 2003 at 8:27 am
Thanks. I'll put the whole thing together now and post the resulting script.
December 17, 2003 at 11:28 am
It works.
Thanks for all the input - Much appreciated.
I used the script on SQL 2000 on which @@Servername didn't seem to work.
For SQL 7.0, use @@servername instead of:
declare @servername varchar(30)
SELECT @servername = CONVERT(varchar(30), SERVERPROPERTY('servername'))
One last thing... Any ideas on how to get this query to run through Firewall 1. Logs don't show dropping/rejecting of any packets along this path?
/*
Description: Checks size of each Db on server and inserts values into stats DB on linked server.
Date: 17/12/2003
*/
select [dbname]=db_name(), * into #sysfiles from sysfiles where 1=2
select [dbname]=db_name(), * into #sysindexes from sysindexes where 1=2
select ServerName,DatabaseName, UsedSpace,FreeSpace,DataDevice, LogDevice, RecordDate into #stats from ServerName.DatabaseName.dbo.DatabaseStats where 1=2
exec sp_MSforeachdb'
use dbcc updateusage (0) with no_infomsgs
insert #sysfiles select ''?'', * from sysfiles
insert #sysindexes select ''?'', * from sysindexes
declare @servername varchar(30)
declare@pagesint
declare @datapage dec(15,2)
declare @datapageMB dec(15,2)
declare @LogpageMB dec(15,2)
declare @logpage dec(15,2)
declare @unallocatedpage decimal(15,2)
declare @bytesperpagedec(15,2)
declare @pagesperMB dec(15,2)
DECLARE @DataPlusLogMB decimal(15,2)
DECLARE @Unallocated decimal(15,2)
SELECT @bytesperpage = low
FROM master.dbo.spt_values
WHERE number = 1
AND type = ''E''
SET @pagesperMB = 1048576 / @bytesperpage
SELECT @servername = CONVERT(varchar(30), SERVERPROPERTY(''servername''))
select @datapage = sum(convert(dec(15),size))
from #sysfiles
where (status & 64 = 0)
and dbname like ''?''
select @logpage = sum(convert(dec(15),size))
from #sysfiles
where (status & 64 <> 0)
and dbname like ''?''
SELECT @unallocatedpage = SUM(CAST(reserved AS decimal(15,0)))
FROM #sysindexes
WHERE indid IN (0, 1, 255)
and dbname like ''?''
SET @DataPlusLogMB = (@datapage + @logpage) / @pagesperMB
SET @Unallocated =(@datapage - @unallocatedpage) / @pagesperMB
SET @DataPageMB = @datapage / @pagesperMB
SET @LogPageMB = @logpage / @pagesperMB
Insert Into #stats(ServerName,DatabaseName, UsedSpace,FreeSpace,DataDevice, LogDevice, RecordDate)
Values(@servername, ''?'', @DataPlusLogMB,@Unallocated,@DataPageMB,@LogPageMB, getdate())
'
declare @servername varchar(30)
SELECT @servername = CONVERT(varchar(30), SERVERPROPERTY('servername'))
If not Exists (select * from ServerName.DatabaseName.dbo.DatabaseStats
where Servername like @Servername
and datediff(day, recorddate, getdate())=0)
Insert Into ServerName.DatabaseName.dbo.DatabaseStats(ServerName,DatabaseName, UsedSpace,FreeSpace,DataDevice, LogDevice, RecordDate)
select * from #stats
--select* from #stats
drop table #sysfiles
drop table #sysindexes
drop table #stats
Viewing 6 posts - 1 through 5 (of 5 total)
You must be logged in to reply to this topic. Login to reply