Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2000 Forums
 SQL Server Administration (2000)
 sp_MSforEachTable Transaction Count

Author  Topic 

AjarnMark
SQL Slashing Gunting Master

3246 Posts

Posted - 2009-09-21 : 18:58:07
SQL Server 2000 with Service Pack 3
Database in question is 160GB in size, running SIMPLE recovery model.

I inherited a server with an interesting blunt-force approach to index maitenance... It has a Scheduled Job that runs once per week, with one Step in it. That step calls a stored procedure in the database. The stored procedure has one command in it:

EXEC sp_MSForeachtable "DBCC DBREINDEX('?','',100)"

Now I would hope that the behavior of sp_MSforEachTable would be to execute separate transactions for each table, and thus not beat up the Transaction Log too much, but I'm not sure how to prove (or disprove) that.

Anyone know for sure whether it does, and how to prove it?

--------------------------------------------
Brand yourself at EmeraldCityDomains.com

robvolk
Most Valuable Yak

15732 Posts

Posted - 2009-09-21 : 21:31:34
It doesn't. You can view the SQL for it in master to confirm.

I wrote my own version to do reindexing of a DB about 120 GB in size that would periodically checkpoint and backup the log to prevent excess growth. If you're interested I can post the code for you.
Go to Top of Page

AjarnMark
SQL Slashing Gunting Master

3246 Posts

Posted - 2009-09-22 : 12:15:00
Hey Rob! Long time... You coming to the PASS Summit this year? Hope to see you there!

I was afraid that was asking too much. I am working on a script that will filter the list of tables based on level of index fragmentation in order to narrow the scope of work initially. I'd love to see the code you've put together, too.

--------------------------------------------
Brand yourself at EmeraldCityDomains.com
Go to Top of Page

robvolk
Most Valuable Yak

15732 Posts

Posted - 2009-09-22 : 12:51:13
I won't be making it to PASS this year, but I should be there next year.

You can probably use Tara's reindexing script, it accepts a minimum fragmentation percentage. I believe you could sp_msforeachtable on everything, and it will only reindex the ones that exceed the minimum:

http://weblogs.sqlteam.com/tarad/archive/2009/08/31/DefragmentingRebuilding-Indexes-in-SQL-server-2005-and-2008.aspx
Go to Top of Page

AjarnMark
SQL Slashing Gunting Master

3246 Posts

Posted - 2009-09-22 : 13:02:40
Ha! I should have known to check Tara's blog. She has a lot of great scripts out there. Although that particular link uses some SQL 2005 specific tricks and this database is on 2000, but I'm sure it will have some good lessons to learn. There is also a script in the SQL 2000 BOL that is written around INDEXDEFRAG instead of DBREINDEX, but I'm tweaking that to see how it works out.

--------------------------------------------
Brand yourself at EmeraldCityDomains.com
Go to Top of Page

robvolk
Most Valuable Yak

15732 Posts

Posted - 2009-09-22 : 13:17:48
I found the code I used, I took out some stuff that was obsolete:

create procedure [dbo].[sp_reindex] @row_table sql_variant=0, @size_limit bigint=0 as
set nocount on
declare @simple bit, @sql varchar(8000), @rows bigint, @max bigint, @c bigint
set @max=power(2,30)

if cast(sql_variant_property(@row_table, 'BaseType') as varchar) like '%char' begin
set @sql=replace('dbcc dbreindex(''?'', '''', 0) with no_infomsgs;', '?', cast(@row_table as varchar(256)))
exec(@sql)
RETURN
end

set @simple=case databasepropertyex(db_name(), 'Recovery') when 'SIMPLE' then 1 else 0 end
set @c=0

if sql_variant_property(@row_table, 'BaseType') in ('bigint','decimal','int','numeric','smallint','tinyint')
set @rows=case when @row_table is null then @max when @row_table=0 then @max else cast(@row_table as bigint) end
else
set @rows=power(2,30)
set @size_limit=case when @size_limit is null then @max*@max when @size_limit=0 then @max*@max else @size_limit*1024 end

declare @tb table(tbl varchar(256), rows bigint, size bigint, i int not null identity(1,1) primary key)

insert @tb(tbl, rows, size)
select quotename(user_name(o.uid)) + '.' + quotename(o.name), sum(i.rows),
cast(sum(i.reserved) as bigint)*8192
from sysindexes i with (nolock) inner join sysobjects o with (nolock) on i.id=o.id
where o.type='U' and i.indid<2 and i.rows<=@rows
group by o.uid, o.name
having cast(sum(i.reserved) as bigint)*8192<@size_limit
order by 2 desc, 1

update @tb set @c=case when @c+abs(size)>@max then abs(size) else @c+abs(size) end,
size=case when @c+abs(size)>@max*2 then -abs(size) else abs(size) end

declare z cursor fast_forward for select tbl, rows, size from @tb
open z
fetch z into @sql, @rows, @size_limit
while @@fetch_status=0 begin
RAISERROR('%s - %d rows', 10, 1, @sql, @rows) with NOWAIT
set @sql=replace('dbcc dbreindex(''?'', '''', 0) with no_infomsgs;', '?', @sql)
if @size_limit<0 set @sql=@sql + ' checkpoint; ' + case @simple when 0 then '
exec master..MakeBackup ''' + db_name() + ''', ''L''' else '' end
exec(@sql)
fetch z into @sql, @rows, @size_limit
end
close z
deallocate z
drop table #files
It's kinda hacky. It can reindex one table at a time, or all tables, or only those less than a certain rowcount or size in bytes. There's a line in there to do a checkpoint and a log backup, you'll have to modify or remove it to meet your needs.
Go to Top of Page

AjarnMark
SQL Slashing Gunting Master

3246 Posts

Posted - 2009-09-23 : 18:35:15
Thanks, I'll check it out.

I have a procedure working that will use DBCC SHOWCONTIG so that I can filter out tables that are minimally fragmented already, but can only get it to work if that procedure is in the database I'm wanting to defrag. I like Tara's 2005 version that uses the DMVs so I can have a central procedure run on any database I want. But until I can kill this SQL 2000 box, guess I'm stuck.

--------------------------------------------
Brand yourself at EmeraldCityDomains.com
Go to Top of Page
   

- Advertisement -