Login or Sign Up to become a member!
LessThanDot Sit Logo

LessThanDot

Data Management

Less Than Dot is a community of passionate IT professionals and enthusiasts dedicated to sharing technical knowledge, experience, and assistance. Inside you will find reference materials, interesting technical discussions, and expert tips and commentary. Once you register for an account you will have immediate access to the forums and all past articles and commentaries.

LTD Social Sitings

Lessthandot twitter Lessthandot Linkedin Lessthandot friendfeed Lessthandot facebook Lessthandot rss

Note: Watch for social icons on posts by your favorite authors to follow their postings on these and other social sites.

Your profile

Search

XML Feeds

Google Ads

« How to use T-SQL to get the command line startup parameters that were used to start SQL ServerHow to get the processid that SQL Server is using if you have multiple instances of SQL Server running »
comments
Rate Post:
submit to reddit Digg!FacebookDotnetkicks

Quite often we want to consolidate query information across all databases (or all user databases). When this question is asked in forums, the usual recommendation is to either try running undocumented sp_MSForEachDB stored procedure or do a loop and use dynamic SQL. The example of such stored procedure can be found, for example, THIRD EXAMPLE - SPROC to enumerate all objects in databases.

The idea occurred to me last night that while we do need a dynamic SQL to solve this problem, we don't really need a loop unless we need a second loop involving looping through all tables.

Here is a script demonstrating this idea - it lists indexes in all databases with their usage. This script was an answer to Help in T-SQL Query thread in MSDN T-SQL forum.

  1. DECLARE @SQL NVARCHAR(MAX)
  2. IF OBJECT_ID('tempdb..#Result','U') IS not NULL
  3.  DROP TABLE #Result
  4. CREATE TABLE #Result (DBName sysname, TableName Sysname, IndexName sysname, USAGE BIGINT)
  5.  
  6. SELECT @SQL = COALESCE(@SQL,'') + CHAR(13) + CHAR(10) + ' use ' + QUOTENAME([Name]) + ';
  7. insert into #Result select ' + QUOTENAME([Name],'''') + ' as DbName,
  8. object_name(i.object_id) as tablename,  i.name as indexname,
  9. s.user_seeks + s.user_scans + s.user_lookups + s.user_updates as usage
  10. from sys.indexes i  
  11. inner join sys.dm_db_index_usage_stats s        
  12. on s.object_id = i.object_id                    
  13. and s.index_id = i.index_id              
  14. and s.database_id = db_id()
  15. where objectproperty(i.object_id, ''IsUserTable'') = 1  
  16. and i.index_id > 0
  17. order by usage;' FROM sys.databases
  18. --print (@SQL)
  19. EXECUTE (@SQL)
  20. SELECT * FROM #Result ORDER BY [DbName],[USAGE]
  21. DROP TABLE #Result

Another example of the same idea you can find in Finding Record with Last Modified date in all tables

Using this same idea you can get a count of all objects in all your databases using this PIVOT query:

  1. DECLARE @Qry NVARCHAR(MAX)
  2. SELECT @Qry = COALESCE(@Qry + CHAR(13) + CHAR(10) + ' UNION ALL ','') + '
  3. select ' + QUOTENAME([Name],'''') + ' as DBName, [AGGREGATE_FUNCTION], [CHECK_CONSTRAINT],[DEFAULT_CONSTRAINT],
  4.  
  5. [FOREIGN_KEY_CONSTRAINT],
  6.  
  7. [SQL_SCALAR_FUNCTION],
  8.  
  9. [CLR_SCALAR_FUNCTION],
  10.  
  11. [CLR_TABLE_VALUED_FUNCTION],
  12.  
  13. [SQL_INLINE_TABLE_VALUED_FUNCTION],
  14.  
  15. [INTERNAL_TABLE],[SQL_STORED_PROCEDURE],[CLR_STORED_PROCEDURE],[PLAN_GUIDE],[PRIMARY_KEY_CONSTRAINT],
  16. [RULE],[REPLICATION_FILTER_PROCEDURE],[SYNONYM],[SERVICE_QUEUE],[CLR_TRIGGER],[SQL_TABLE_VALUED_FUNCTION],[SQL_TRIGGER],
  17. [TABLE_TYPE],[USER_TABLE],[UNIQUE_CONSTRAINT],[VIEW],[EXTENDED_STORED_PROCEDURE]
  18.  
  19. from (select [Name], type_Desc from ' + QUOTENAME([Name]) + '.sys.objects where is_ms_shipped = 0) src
  20. PIVOT (count([Name]) FOR type_desc in ([AGGREGATE_FUNCTION], [CHECK_CONSTRAINT],[DEFAULT_CONSTRAINT],
  21.  
  22. [FOREIGN_KEY_CONSTRAINT],
  23.  
  24. [SQL_SCALAR_FUNCTION],
  25.  
  26. [CLR_SCALAR_FUNCTION],
  27.  
  28. [CLR_TABLE_VALUED_FUNCTION],
  29.  
  30. [SQL_INLINE_TABLE_VALUED_FUNCTION],
  31.  
  32. [INTERNAL_TABLE],[SQL_STORED_PROCEDURE],[CLR_STORED_PROCEDURE],[PLAN_GUIDE],[PRIMARY_KEY_CONSTRAINT],
  33. [RULE],[REPLICATION_FILTER_PROCEDURE],[SYNONYM],[SERVICE_QUEUE],[CLR_TRIGGER],[SQL_TABLE_VALUED_FUNCTION],[SQL_TRIGGER],
  34. [TABLE_TYPE],[USER_TABLE],[UNIQUE_CONSTRAINT],[VIEW],[EXTENDED_STORED_PROCEDURE])) pvt' FROM sys.databases
  35. WHERE [name] NOT IN ('master','tempdb','model','msdb') ORDER BY [Name]
  36.  
  37. EXECUTE(@Qry)

You can only list types you're interested in, of course.

The script below will give you a count of records in every table in a database:

  1. DECLARE  @DynamicSQL NVARCHAR(MAX)
  2.  
  3. SELECT   @DynamicSQL = COALESCE(@DynamicSQL + CHAR(13) + ' UNION ALL ' + CHAR(13),
  4.                                 '') +
  5.                                 'SELECT ' + QUOTENAME(table_schema,'''') + ' as [Schema Name], ' +
  6.                                 QUOTENAME(TABLE_NAME,'''') +
  7.                                 ' as [Table Name], COUNT(*) AS [Records Count] FROM ' +
  8.                                 QUOTENAME(Table_schema) + '.' + QUOTENAME(TABLE_NAME)
  9. FROM     INFORMATION_SCHEMA.TABLES
  10. ORDER BY TABLE_NAME
  11.  
  12. --print (@DynamicSQL) -- we may want to use PRINT to debug the SQL
  13. EXEC( @DynamicSQL)

Quick row count in all tables in all databases in the server instance (you can exclude system databases from that loop, obviously)

  1. DECLARE @SQL NVARCHAR(MAX)
  2.  
  3. SET @SQL = ''
  4. --select * from sys.databases
  5. SELECT @SQL = @SQL + CHAR(13) + 'USE ' + QUOTENAME([name]) + ';
  6. SELECT ' +QUOTENAME([name],'''') + 'as [Database Name],
  7.   SchemaName=s.name
  8.  ,TableName=t.name
  9.  ,CreateDate=t.create_date
  10.  ,ModifyDate=t.modify_date
  11.  ,p.rows
  12.  ,DataInKB=sum(a.used_pages)*8
  13. FROM sys.schemas s
  14. JOIN sys.tables t on s.schema_id=t.schema_id
  15. JOIN sys.partitions p on t.object_id=p.object_id
  16. JOIN sys.allocation_units a on a.container_id=p.partition_id
  17. GROUP BY s.name, t.name, t.create_date, t.modify_date, p.rows
  18. ORDER BY SchemaName, TableName' FROM sys.databases  
  19.  
  20. EXECUTE (@SQL)

Another way with less info:

  1. DECLARE @SQL NVARCHAR(MAX)
  2.  
  3. SET @SQL = ''
  4. --select * from sys.databases
  5. SELECT @SQL = @SQL + CHAR(13) + 'USE ' + QUOTENAME([name]) + ';
  6. SELECT ' +QUOTENAME([name],'''') + 'as [Database Name], so.name AS [Table Name],  
  7.    rows AS [RowCount]  
  8. FROM sysindexes AS si  
  9.    join sysobjects AS so on si.id = so.id  
  10. WHERE indid IN (0,1)  
  11.    AND xtype = ''U''' FROM sys.databases  
  12.  
  13. EXECUTE (@SQL)

Here is a script showing sizes from all tables in a database.

  1. --exec sp_MSforeachtable 'print ''?'' exec sp_spaceused ''?'''
  2. IF OBJECT_ID('tempdb..#TablesSizes') IS NOT NULL
  3.    DROP TABLE #TablesSizes
  4.    
  5. CREATE TABLE #TablesSizes (TableName sysname, ROWS BIGINT, reserved VARCHAR(100), DATA VARCHAR(100), index_size VARCHAR(100), unused VARCHAR(100))
  6.  
  7. DECLARE @SQL VARCHAR(MAX)
  8. SELECT @SQL = COALESCE(@SQL,'') + '
  9. insert into #TablesSizes execute sp_spaceused ' + QUOTENAME(Table_Name,'''') FROM INFORMATION_SCHEMA.TABLES
  10.  
  11. --print (@SQL)
  12. EXECUTE (@SQL)
  13.  
  14. SELECT * FROM #TablesSizes ORDER BY TableName

Here is a script showing database files sizes for all databases

  1. DECLARE @SQL VARCHAR(MAX)
  2. SELECT @SQL =COALESCE(@SQL + CHAR(13) + 'UNION ALL
  3. ' ,'') + 'SELECT ''' + name + ''' AS DBNAME,' +
  4. 'sum(size * 8 /1024.0) AS MB from ' + QUOTENAME(name) + '.dbo.sysfiles'
  5. FROM sys.databases
  6. ORDER BY name
  7.  
  8. EXECUTE (@SQL)

The possibilities are endless.




*** Remember, if you have a SQL related question, try our Microsoft SQL Server Programming forum or our Microsoft SQL Server Admin forum

About the Author

User bio imageNaomi Nosonovsky, Senior Software Developer, has more than 15 years of enterprise experience in analysis, design, development and implementation of high-performance client/server data management solutions. She is a personality of the year 2008 and 2009 at www.universalthread.com in .NET, SQL Server & VFP categories. She is also an All Star contributor at forums.asp.net and MSDN T-SQL forum.
Social SitingsFacebookLinkedIndeliciousLTD RSS Feed
819 views
submit to reddit Digg!FacebookDotnetkicks

Comments and Feedback

3 comments

Comment from: Ted Krueger (onpnt) [Member] Email
Good Tip Naomi! Just be careful running this kind of thing in a large installation and during any point of normal operating times. It will suck the life out of teh DB Server as far as IO and high CPU goes
05/16/10 @ 17:08
Comment from: Naomi [Member] Email
Thanks. Do you think traditional cursor based approach is safer?
05/16/10 @ 17:29
Comment from: Ted Krueger (onpnt) [Member] Email
My recommendation is nothing like this should be run during peak times unless you are having problems to the point it calls for it. DBA tasks like these can be the most taxing on the system seeing as they go to disk and other resources almost exclusively. So cursor or not, you will slow the system by running them.

Take a look here and to Paul's blog
http://blogs.lessthandot.com/index.php/DataMgmt/DBAdmin/think-before-you-f5-on-dmvs
05/17/10 @ 06:07

Leave a comment


Your email address will not be revealed on this site.

Your URL will be displayed.
(Line breaks become <br />)
(Name, email & website)
(Allow users to contact you through a message form (your email will not be revealed.)