Looks like there was a typo in Step 2. Here's the new script.
/****** Object: StoredProcedure [dbo].[SelectAllServersFragmentedTables] Script Date: 09/12/2011 09:07:05 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- ==========================================================================
-- Author: Kimberly Killian
-- Create date: 5/19/11
-- Description:Get the fragmented index's in each server/database (laptops)
-- ==========================================================================
CREATE procedure [dbo].[SelectAllServersFragmentedTables]
@p_FragmentedLimit decimal = 5.0
as
declare @err int,
@rc int,
@cmd varchar(8000),
@cmd2 varchar(8000),
@ServerName sysname,
@cmdmailvarchar(50),
@cmdSprocDefrag varchar (50)
set nocount on
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ServerList_frag]') AND type in (N'U'))
DROP TABLE [dbo].[ServerList_frag]
CREATE TABLE [dbo].[ServerList_frag](
[Server] [varchar](128) NOT NULL,
CONSTRAINT [PK_SSIS_ServerList_frag] PRIMARY KEY CLUSTERED
([Server] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 99) ON [PRIMARY]
) ON [PRIMARY]
-- Load table with server names
-- This will only work if XP_CMDSHELL is Enabled
Create table #Server ( [Server] [varchar](128) )
Insert Into #Server
Exec xp_cmdshell 'sqlcmd /Lc'
Insert Into SSIS_ServerList_frag ([Server])
select [Server] from #Server where SERVER in (select [SERVER] from dbo.ServerList where Skip_SQL_Overview = 'false')
DROP Table #Server
---------------------------------------------------------------------------------------------------------
-- Truncate the central table with the fragmentation information
---------------------------------------------------------------------------------------------------------
TRUNCATE TABLE Fragmented_reorg_queries
---------------------------------------------------------------------------------------------------------
-- Loop on Server list and find fragmented tables where they haven't cleaned up for at least 14 days
---------------------------------------------------------------------------------------------------------
declare SrvCursB cursor for
select Server from dbo.ServerList_frag where SERVER not in
(select distinct ServerName from dbo.Fragmented_reorg_queries_history group by servername having max(LastChecked) >= getdate()-14)
open SrvCursB
fetch SrvCursB into @ServerName
while @@FETCH_STATUS = 0
BEGIN
--send warning email to remote servers
select @cmdmail = 'sendemail_do_not_disconnect ' + @ServerName
exec (@cmdmail)
-- Create a table in tempdb that will be populated at the remote
-- server and later be accessed from the central database
-- (Command passed to osql should be in one line, no <CR>):
--Check DB Consistency
select @cmd = 'DBCC CHECKDB WITH NO_INFOMSGS;' +
'if exists (select 1 from ' + @servername + '.tempdb.dbo.sysobjects ' +
'where type = ''U'' AND NAME = ''fraglist'') ' +
'drop table tempdb.dbo.fraglist;' +
'CREATE TABLE tempdb.dbo.fraglist (' +
'ServerName sysname,' +
'DatabaseName sysname,' +
'ObjectName CHAR (255),' +
'ObjectId INT,' +
'IndexName CHAR (255),' +
'IndexId INT,' +
'Lvl INT,' +
'CountPages INT,' +
'CountRows INT, ' +
'MinRecSize INT,' +
'MaxRecSize INT,' +
'AvgRecSize INT,' +
'ForRecCount INT,' +
'Extents INT,' +
'ExtentSwitches INT,' +
'AvgFreeBytes INT,' +
'AvgPageDensity INT,' +
'ScanDensity DECIMAL,' +
'BestCount INT,' +
'ActualCount INT,' +
'LogicalFrag DECIMAL,' +
'ExtentFrag DECIMAL) '
select @cmd2 = 'sqlcmd -E -S"' + @ServerName + '" -Q "' +
@cmd + '"'
exec master..xp_cmdshell @cmd2
select @err = @@error
IF @err <> 0
begin
select 'ERROR Creating the table in tempdb for SERVER - '+
@ServerName
return -1
end
/*Query the fragmenation data into a table on tempdb for each remote server
Insert fragmentation information into a temporary table.
Insert fragmentation information including server name and database name into
the remote table created in tempdb.
Create defrag/reindex queries and write to a table to be used later.
Write defrag/reindex queries to a history table to be used later*/
select @cmd =
'exec [' + @ServerName + '].master.dbo.sp_msforeachdb ' +
'''use [?]; print ''''?'''';
if ''''?'''' in (''''tempdb'''',''''msdb'''',''''master'''',
''''model'''',''''Northwind5'''',''''pubs'''',''''ReportServerTempDB'''',''''ReportServer'''')
return
create table #t (cmd varchar(max));
insert into #t select
''''SET ARITHABORT ON
SET QUOTED_IDENTIFIER ON;
dbcc showcontig() with tableresults, all_indexes;''''
declare @cmd varchar(max)
declare curs_tmp cursor for select cmd from #t
open curs_tmp
fetch curs_tmp into @cmd
while @@fetch_status = 0
begin
select ObjectName, ObjectId, IndexName, IndexId, Lvl,
CountPages, CountRows, MinRecSize, MaxRecSize,
AvgRecSize, ForRecCount, Extents, ExtentSwitches,
AvgFreeBytes, AvgPageDensity, ScanDensity,
BestCount, ActualCount, LogicalFrag, ExtentFrag
into #fraglist from tempdb.dbo.fraglist where 1=2
insert into #fraglist exec (@cmd)
insert into tempdb.dbo.fraglist
select ''''' + @ServerName + ''''',
db_name(),* from #fraglist
WHERE IndexID not in (0,255)
And LogicalFrag > ''''' +
convert(varchar(10),@p_FragmentedLimit) +
'''''
drop table #fraglist
fetch curs_tmp into @cmd
end
close curs_tmp
deallocate curs_tmp
drop table #t;
SET ARITHABORT OFF
SET QUOTED_IDENTIFIER OFF;'''
exec (@cmd)
select @err = @@error
IF @err <> 0
begin
select 'ERROR Collecting fragmentation information for ' +
'SERVER - ' + @ServerName
return -1
end
-- Insert the fragmentation details to the central (local) table
select @cmd = 'insert into FragmentedTables select * from ['+
@ServerName + '].tempdb.dbo.fraglist'
exec (@cmd)
select @err = @@error
IF @err <> 0
begin
select 'ERROR selecting data from remote table for ' +
'SERVER - ' + @ServerName
return -1
end
--get the fragmented tables and generate scripts
--save the history
select @cmd = 'INSERT INTO [SQL_Overview].[dbo].[Fragmented_reorg_queries]
([ServerName] ,[DatabaseName] ,[query])
SELECT ServerName, DatabaseName,
''ALTER INDEX'' + '' '' + RTRIM(IndexName) + '' '' + ''ON '' + RTRIM([ObjectName]) + '' '' + ''REORGANIZE'' as query
FROM [SQL_Overview].[dbo].[FragmentedTables]
where LogicalFrag between 5 and 30
INSERT INTO [SQL_Overview].[dbo].[Fragmented_reorg_queries]
([ServerName] ,[DatabaseName] ,[query])
SELECT ServerName, DatabaseName,
''ALTER INDEX'' + '' '' + RTRIM(IndexName) + '' '' + ''ON '' + RTRIM([ObjectName]) + '' '' + ''REBUILD'' as query
FROM [SQL_Overview].[dbo].[FragmentedTables]
where LogicalFrag >= 31
INSERT INTO [SQL_Overview].[dbo].[Fragmented_reorg_queries_history]
([ServerName] ,[DatabaseName] , [Query], [LastChecked])
SELECT [ServerName], [DatabaseName], [query], GETDATE() as LastChecked
FROM [SQL_Overview].[dbo].[Fragmented_reorg_queries]'
exec (@cmd)
--Run the queries generated for each server on each server
select @cmdSprocDefrag = 'defrag_Fragmented_tables ' + @ServerName
exec(@cmdSprocDefrag)
-- Drop the remote table in tempdb
select @cmd =
'if exists (select 1 from tempdb.dbo.sysobjects ' +
'where type = ''U'' AND NAME = ''fraglist'') ' +
'drop table tempdb.dbo.fraglist'
select @cmd2 = 'sqlcmd -E -S"' + @ServerName + '" -Q "' + @cmd +
'"'
exec master..xp_cmdshell @cmd2
select @err = @@error
IF @err <> 0
begin
select 'ERROR dropping remote table for SERVER - ' +
@ServerName
return -1
end
--run query to check level of fragmentation after defrag
--same as above
select @cmd = 'if exists (select 1 from tempdb.dbo.sysobjects ' +
'where type = ''U'' AND NAME = ''fraglistafter'') ' +
'drop table tempdb.dbo.fraglistafter;' +
'CREATE TABLE tempdb.dbo.fraglistafter (' +
'ServerName sysname,' +
'DatabaseName sysname,' +
'ObjectName CHAR (255),' +
'ObjectId INT,' +
'IndexName CHAR (255),' +
'IndexId INT,' +
'Lvl INT,' +
'CountPages INT,' +
'CountRows INT, ' +
'MinRecSize INT,' +
'MaxRecSize INT,' +
'AvgRecSize INT,' +
'ForRecCount INT,' +
'Extents INT,' +
'ExtentSwitches INT,' +
'AvgFreeBytes INT,' +
'AvgPageDensity INT,' +
'ScanDensity DECIMAL,' +
'BestCount INT,' +
'ActualCount INT,' +
'LogicalFrag DECIMAL,' +
'ExtentFrag DECIMAL) '
select @cmd2 = 'sqlcmd -E -S"' + @ServerName + '" -Q "' +
@cmd + '"'
exec master..xp_cmdshell @cmd2
select @err = @@error
IF @err <> 0
begin
select 'ERROR Creating the table in tempdb for SERVER - '+
@ServerName
return -1
end
/*Query the fragmenation data into a table on tempdb for each remote server
Insert fragmentation information into a temporary table.
Insert fragmentation information including server name and database name into
the remote table created in tempdb. */
select @cmd =
'exec [' + @ServerName + '].master.dbo.sp_msforeachdb ' +
'''use [?]; print ''''?'''';
if ''''?'''' in (''''tempdb'''',''''msdb'''',''''master'''',
''''model'''',''''Northwind5'''',''''pubs'''')
return
create table #a (cmd varchar(max));
insert into #a select
''''SET ARITHABORT ON
SET QUOTED_IDENTIFIER ON;
dbcc showcontig() with tableresults, all_indexes;''''
declare @cmd varchar(max)
declare curs_tmpafter cursor for select cmd from #a
open curs_tmpafter
fetch curs_tmpafter into @cmd
while @@fetch_status = 0
begin
select ObjectName, ObjectId, IndexName, IndexId, Lvl,
CountPages, CountRows, MinRecSize, MaxRecSize,
AvgRecSize, ForRecCount, Extents, ExtentSwitches,
AvgFreeBytes, AvgPageDensity, ScanDensity,
BestCount, ActualCount, LogicalFrag, ExtentFrag
into #fraglistafter from tempdb.dbo.fraglistafter where 1=2
insert into #fraglistafter exec (@cmd)
insert into tempdb.dbo.fraglistafter
select ''''' + @ServerName + ''''',
db_name(),* from #fraglistafter
WHERE IndexID not in (0,255)
And LogicalFrag > ''''' +
convert(varchar(10),@p_FragmentedLimit) +
'''''
drop table #fraglistafter
fetch curs_tmpafter into @cmd
end
close curs_tmpafter
deallocate curs_tmpafter
drop table #a;
SET ARITHABORT OFF
SET QUOTED_IDENTIFIER OFF'''
exec (@cmd)
select @err = @@error
IF @err <> 0
begin
select 'ERROR Collecting fragmentation information for ' +
'SERVER - ' + @ServerName
return -1
end
-- Insert the fragmentation details to the central (local) table
select @cmd = 'insert into FragmentedTablesAfterDefragRun select * from ['+
@ServerName + '].tempdb.dbo.fraglistafter'
exec (@cmd)
select @err = @@error
IF @err <> 0
begin
select 'ERROR selecting data from remote table for ' +
'SERVER - ' + @ServerName
return -1
end
-- Drop the remote table in tempdb, update system index's if needed then run update stats
select @cmd =
'if exists (select 1 from tempdb.dbo.sysobjects ' +
'where type = ''U'' AND NAME = ''fraglistafter'') ' +
'drop table tempdb.dbo.fraglistafter; EXEC sp_updatestats;'
select @cmd2 = 'sqlcmd -E -S"' + @ServerName + '" -Q "' + @cmd +
'"'
exec master..xp_cmdshell @cmd2
select @err = @@error
IF @err <> 0
begin
select 'ERROR dropping remote table for SERVER - ' +
@ServerName
return -1
end
--send completion email to remote servers
select @cmdmail = 'sendemail_All_Clear ' + @ServerName
exec (@cmdmail)
fetch SrvCursB into @ServerName
END
close SrvCursB
deallocate SrvCursB
GO
Thanks,
Kimberly Killian
Sr. DBA / DB Engineer
www.sitedataview.com
Follow me on Twitter
Follow me on Facebook