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

    « SQL Advent 2011 Day 1: Date and timeAnecdotes about SQL AKA post 400 »
    comments

    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 procedures 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.

    Table of Contents:

    Indexes in all databases with their usage
    Indexes in all databases with their physical stats
    Count of all objects in all databases
    Record Count in every table in a database
    Quick Record Count in All Tables in All Databases
    Quick Record Count in All Tables in All Databases (2)
    Sizes of All Tables in a Database
    Database Files Sizes in All Databases
    Database Files Sizes in All Databases and used space
    Backup All Databases with Compression (SQL 2008)
    All Schema Names in All Databases
    List of All Tables in All Databases
    List of All Tables in All Databases (2)
    List of all Stored Procedures in All Databases

    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.

    Indexes in all databases with their usage

    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



    Indexes in all databases with their physical stats

    1. declare @SQL nvarchar(max)
    2. set @SQL = ''
    3. select @SQL = @SQL +
    4. 'Select ' + quotename(name,'''') + ' as [DB Name],
    5. object_Name(PS.Object_ID,' + convert(varchar(10),database_id) + ') as [Object],
    6. I.Name as [Index Name], PS.Partition_Number, PS.Index_Type_Desc,
    7. PS.alloc_unit_type_desc,    PS.index_depth, PS.index_level,
    8. PS.avg_fragmentation_in_percent,    PS.fragment_count,  PS.avg_fragment_size_in_pages,
    9. PS.page_count,  PS.avg_page_space_used_in_percent,  PS.record_count,   
    10. PS.ghost_record_count,  PS.version_ghost_record_count,
    11. PS.min_record_size_in_bytes,    PS.max_record_size_in_bytes,    PS.avg_record_size_in_bytes,
    12. PS.forwarded_record_count,  PS.compressed_page_count
    13. from ' + quotename(name) + '.sys.dm_db_index_physical_stats(' +
    14. convert(varchar(10),database_id) + ', NULL, NULL, NULL, NULL) PS
    15. INNER JOIN ' + quotename(name) +
    16. '.sys.Indexes I on PS.Object_ID = I.Object_ID and PS.Index_ID = I.Index_ID '
    17. + CHAR(13)
    18.  
    19.  from sys.databases where state_desc = 'ONLINE'
    20.  
    21. execute(@SQL)

    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:

    Count of all objects in all databases

    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:

    Record Count 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)

    Quick Record Count in All Tables in All Databases

    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:

    Quick Record Count in All Tables in All Databases

    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.

    Sizes of 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

    Before I show the T-SQL code I'd like to point to this very interesting blog as how to get database sizes in all SQL Server instances using PowerShell

    Database Files Sizes in All Databases

    1. create  table #FileSizes (DBName sysname, [File Name] varchar(max), [Physical Name] varchar(max),
    2. Size decimal(12,2))
    3. declare @SQL nvarchar(max)
    4. set @SQL = ''
    5. select @SQL = @SQL + 'USE'  + QUOTENAME(name) + '
    6. insert into #FileSizes
    7. select ' + QUOTENAME(name,'''') + ', Name, Physical_Name, size/1024.0 from sys.database_files '
    8. from sys.databases
    9.  
    10. execute (@SQL)
    11. select * from #FileSizes order by DBName, [File Name]


    You can also find the script to show all database sizes using sp_MsForEachDB here. See also this relevant thread at MSDN.

    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)


    Database Files Sizes in All Databases and used space

    Note, that this script assumes that database files have the same name as the database itself. If this is not true, this script will not return correct result.

    1. create table #Test (DbName sysname, TotalSize decimal(20,2), Used decimal(20,2), [free space percentage] decimal(20,2))
    2.  
    3. declare @SQL nvarchar(max)
    4. select @SQL = coalesce(@SQL,'') +
    5. 'USE ' + QUOTENAME(Name) + '
    6. insert into #Test
    7. select DB.name, ssf.size*8 as total,
    8. FILEPROPERTY (AF.name, ''spaceused'')*8 as used,
    9. ((ssf.size*8) - (FILEPROPERTY (AF.name, ''spaceused'')*8))*100/(ssf.size*8) as [free space percentage]
    10. from sys.sysALTfiles AF
    11. inner join sys.sysfiles ssf on ssf.name=AF.name COLLATE SQL_Latin1_General_CP1_CI_AS
    12. INNER JOIN sys.databases DB ON AF.dbid=DB.database_id
    13. where ssf.groupid<>1' from sys.databases
    14.  
    15. execute(@SQL)
    16.  
    17. select * from #Test order by DbName



    This script will backup all databases (using compression):

    Backup All Databases with Compression (SQL 2008)

    1. Declare @ToExecute VarChar(8000)
    2.  
    3. Select @ToExecute = Coalesce(@ToExecute + 'Backup Database ' + quotename([Name]) +
    4. ' To Disk = ''C:\SQL DB Backups\All DBs\' + [Name] + '.bak''
    5. WITH NOFORMAT, NOINIT,  
    6. SKIP, NOREWIND, NOUNLOAD, COMPRESSION,  STATS = 10' + char(13),'')
    7.  
    8. From sys.databases
    9.  
    10. Where [Name] Not In ('tempdb') and databasepropertyex ([Name],'Status') = 'online'
    11.  
    12. Execute (@ToExecute)
    13.  
    14. --print @ToExecute

    Get all schema names in all databases:

    All Schema Names in All Databases

    1. declare @Sql nvarchar(max)
    2. create table AllDBSchemas ([DB Name] sysname, [Schema Name] sysname)
    3.  
    4. select @Sql = coalesce(@Sql,'') + '
    5. insert into AllDBSchemas
    6.  
    7. select ' + QUOTENAME(name,'''') + ' as [DB Name], [Name] as [Schema Name] from ' +
    8. QUOTENAME(Name) + '.sys.schemas order by [DB Name],[Name];' from sys.databases
    9. order by name
    10.  
    11. execute(@SQL)
    12.  
    13. select * from AllDBSchemas order by [DB Name],[SCHEMA NAME]


    List of All Tables in All Databases

    1. CREATE TABLE AllTables ([DB Name] sysname, [Schema Name] sysname, [Table Name] sysname)
    2.  
    3. DECLARE @SQL NVARCHAR(MAX)
    4.  
    5. SELECT @SQL = COALESCE(@SQL,'') + '
    6. insert into AllTables
    7.  
    8. select ' + QUOTENAME(name,'''') + ' as [DB Name], [Table_Schema] as [Table Schema], [Table_Name] as [Table Name] from ' +
    9. QUOTENAME(Name) + '.INFORMATION_SCHEMA.Tables;' FROM sys.databases
    10. ORDER BY name
    11.  
    12. EXECUTE(@SQL)
    13.  
    14. SELECT * FROM AllTables ORDER BY [DB Name],[SCHEMA NAME], [Table Name]

    Alternative way to get all tables in all databases:

    List of All Tables in All Databases

    1. if object_ID('TempDB..#AllTables','U') IS NOT NULL drop table #AllTables
    2. CREATE TABLE #AllTables ([DB Name] sysname, [Schema Name] nvarchar(128) NULL, [Table Name] sysname, create_date datetime, modify_date datetime)
    3.  
    4. DECLARE @SQL NVARCHAR(MAX)
    5.  
    6. SELECT @SQL = COALESCE(@SQL,'') + 'USE ' + quotename(name) + '
    7. insert into #AllTables
    8. select ' + QUOTENAME(name,'''') + ' as [DB Name], schema_name(schema_id) as [Table Schema], [Name] as [Table Name], Create_Date, Modify_Date
    9. from ' +
    10. QUOTENAME(Name) + '.sys.Tables;' FROM sys.databases
    11. ORDER BY name
    12. --print @SQL
    13. EXECUTE(@SQL)



    List of all Stored Procedures in All Databases

    1. create table #SPList ([DB Name] sysname, [SP Name] sysname, create_date datetime, modify_date datetime)
    2.  
    3. declare @SQL nvarchar(max)
    4. set @SQL = ''
    5. select @SQL = @SQL + ' insert into #SPList
    6. select ' + QUOTENAME(name, '''') + ', name, create_date, modify_date
    7. from ' + QUOTENAME(name) + '.sys.procedures' from sys.databases
    8.  
    9. execute (@SQL)
    10.  
    11. select * from #SPList order by [DB Name], [SP Name]

    Database Files Growth:

    1. --select * from sys.sysfiles  
    2.  
    3. declare @SQL nvarchar(max)
    4. select @SQL = coalesce(@SQL + '
    5. UNION ALL ','') +
    6.  
    7. 'SELECT CONVERT(varchar(100),
    8. SERVERPROPERTY(''Servername'')) AS Server, ' +
    9. quotename(name,'''') +'  as DatabaseName,
    10.    CAST(name as varchar(128)) COLLATE SQL_Latin1_General_CP1_CI_AS as name,
    11.    CAST(filename as varchar(128)) COLLATE SQL_Latin1_General_CP1_CI_AS as FileName,
    12.    Autogrowth = ''Autogrowth: ''
    13.        +
    14.        CASE
    15.            WHEN (status & 0x100000 = 0 AND CEILING((growth * 8192.0) / (1024.0 * 1024.0)) = 0.00) OR growth = 0 THEN ''None''
    16.            WHEN status & 0x100000 = 0 THEN ''By '' +
    17.            CONVERT(VARCHAR,CEILING((growth * 8192.0) / (1024.0 * 1024.0))) + '' MB''
    18.            ELSE ''By '' + CONVERT(VARCHAR,growth) + '' percent''
    19.        END
    20.        +
    21.        CASE
    22.            WHEN (status & 0x100000 = 0 AND CEILING((growth * 8192.0) / (1024.0 * 1024.0)) = 0.00) OR growth = 0 THEN ''''
    23.            WHEN CAST([maxsize] * 8.0 / 1024 AS DEC(20,2)) <= 0.00 THEN '', unrestricted growth''
    24.            ELSE '', restricted growth to '' + CAST(CAST([maxsize] * 8.0 / 1024 AS DEC(20)) AS VARCHAR) + '' MB''
    25.        END
    26. FROM '  + quotename(name) + '.sys.sysfiles  s'
    27. from sys.databases
    28.  
    29. set @SQL = @SQL + '
    30. ORDER BY DatabaseName'
    31.  
    32. print @SQL
    33.  
    34. 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

    Naomi 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 for 2008, 2009, 2010 and 2011 at www.universalthread.com in .NET, SQL Server & VFP categories. She is also an All Star contributor/MCC Community Contributor at forums.asp.net and MSDN T-SQL forum.
    Social SitingsFacebookLinkedIndeliciousLTD RSS Feed
    13854 views
    InstapaperVote on HN

    17 comments

    Comment from: Ted Krueger (onpnt) [Member]
    Ted Krueger (onpnt) 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 Nosonovsky [Member]
    Naomi Nosonovsky Thanks. Do you think traditional cursor based approach is safer?
    05/16/10 @ 17:29
    Comment from: Ted Krueger (onpnt) [Member]
    Ted Krueger (onpnt) 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
    Think before you F5 on DMVs
    05/17/10 @ 06:07
    Comment from: Rithika jain [Visitor] Email
    Rithika jain Thanks Naom1 ! You rock .

    But the script used for "Database Files Sizes in All Databases and used space " will not return appropriate results when the logfile physical name is same for other database .

    For example i have two databases named as Test and Test1 where as the physical name is testlog for both the databases . In this case output returned is wrong ...
    12/21/10 @ 02:26
    Comment from: Naomi Nosonovsky [Member]
    Naomi Nosonovsky Hi Rithika,

    Thanks a lot for the comment. I'll re-visit this code and make a comment for now.
    12/21/10 @ 07:10
    Comment from: Surendra [Visitor]
    Surendra Your pic here is superb... than the one in the MSDN
    08/23/11 @ 15:29
    Comment from: Naomi Nosonovsky [Member]
    Naomi Nosonovsky This is not a picture, it's an image. My friend sent it to me few years back, I liked it and used.
    08/23/11 @ 15:41
    Comment from: Willy [Visitor]
    Willy Checks code for now.. thanks for posting :)
    11/30/11 @ 12:52
    Comment from: VoIP SIP SDK [Visitor] Email
    VoIP SIP SDK Coding is very clear and easy for learning.This is also a source of coding.
    12/27/11 @ 09:42
    Comment from: Dhinesh [Visitor] Email
    Dhinesh Thanks. It is very useful and good learnig stuff
    05/29/12 @ 00:47
    Comment from: tgrignon [Member]
    tgrignon Very useful Naomi. Thanks!
    08/29/12 @ 07:21
    Comment from: Pablo [Visitor]
    Pablo Thank you for this post!
    This is a novel and neat approach to do tasks which I normally use (horrible) cursors with (horrible) dynamic SQL.

    Every search for a solution without cursors took me to forums which say 'oh, don't use cursors - they're horrible', yet completely fail to provide a practical, non-trivial example of a solution.

    Thanks for posting these code examples.
    10/11/12 @ 03:28
    Comment from: Tahir Khalid [Member] Email
    Great article, just saved my day. Would be great if there was a file with the above SQL in it for us mere mortals to download
    12/12/12 @ 09:24
    Comment from: Naomi Nosonovsky [Member]
    Naomi Nosonovsky I think I was creating the samples for each particular scenario separately, so I don't really have all these scripts in one file, they are spread in different files and some may not be even saved.
    12/12/12 @ 09:48
    Comment from: Tahir Khalid [Member] Email
    An "SQL Tool Belt" post might be warranted ;-)
    12/12/12 @ 11:03
    Comment from: Nikhil Godkar [Visitor]
    Nikhil Godkar Great article,Thank you for this post!
    12/29/12 @ 07:39
    Comment from: emekm [Visitor]
    emekm Great article!!
    very usefull sql queries
    thank you
    03/12/13 @ 02:54

    Leave a comment


    Your email address will not be revealed on this site.

    To mislead the spambots.

    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.)