Listing information about all database files in SQL Server - sql-server

Is it possible to list information about the files (MDF/LDF) of all databases on an SQL Server?
I'd like to get a list showing which database is using what files on the local disk.
What I tried:
exec sp_databases all databases
select * from sys.databases shows a lot of information about each database - but unfortunately it doesn't show the files used by each database.
select * from sys.database_files shows the mdf/ldf files of the master database - but not the other databases

You can use sys.master_files.
Contains a row per file of a database as stored in the master
database. This is a single, system-wide view.

If you want get location of Database you can check Get All DBs Location.
you can use sys.master_files for get location of db and sys.database to get db name
SELECT
db.name AS DBName,
type_desc AS FileType,
Physical_Name AS Location
FROM
sys.master_files mf
INNER JOIN
sys.databases db ON db.database_id = mf.database_id

I am using script to get empty space in each file:
Create Table ##temp
(
DatabaseName sysname,
Name sysname,
physical_name nvarchar(500),
size decimal (18,2),
FreeSpace decimal (18,2)
)
Exec sp_msforeachdb '
Use [?];
Insert Into ##temp (DatabaseName, Name, physical_name, Size, FreeSpace)
Select DB_NAME() AS [DatabaseName], Name, physical_name,
Cast(Cast(Round(cast(size as decimal) * 8.0/1024.0,2) as decimal(18,2)) as nvarchar) Size,
Cast(Cast(Round(cast(size as decimal) * 8.0/1024.0,2) as decimal(18,2)) -
Cast(FILEPROPERTY(name, ''SpaceUsed'') * 8.0/1024.0 as decimal(18,2)) as nvarchar) As FreeSpace
From sys.database_files
'
Select * From ##temp
drop table ##temp
Size is expressed in KB.

I've created this query:
SELECT
db.name AS [Database Name],
mf.name AS [Logical Name],
mf.type_desc AS [File Type],
mf.physical_name AS [Path],
CAST(
(mf.Size * 8
) / 1024.0 AS DECIMAL(18, 1)) AS [Initial Size (MB)],
'By '+IIF(
mf.is_percent_growth = 1, CAST(mf.growth AS VARCHAR(10))+'%', CONVERT(VARCHAR(30), CAST(
(mf.growth * 8
) / 1024.0 AS DECIMAL(18, 1)))+' MB') AS [Autogrowth],
IIF(mf.max_size = 0, 'No growth is allowed', IIF(mf.max_size = -1, 'Unlimited', CAST(
(
CAST(mf.max_size AS BIGINT) * 8
) / 1024 AS VARCHAR(30))+' MB')) AS [MaximumSize]
FROM
sys.master_files AS mf
INNER JOIN sys.databases AS db ON
db.database_id = mf.database_id

Executing following sql (It will only work when you don't have multiple mdf/ldf files for same database)
SELECT
db.name AS DBName,
(select mf.Physical_Name FROM sys.master_files mf where mf.type_desc = 'ROWS' and db.database_id = mf.database_id ) as DataFile,
(select mf.Physical_Name FROM sys.master_files mf where mf.type_desc = 'LOG' and db.database_id = mf.database_id ) as LogFile
FROM sys.databases db
will return this output
DBName DataFile LogFile
--------------------------------------------------------------------------------
master C:\....\master.mdf C:\....\mastlog.ldf
tempdb C:\....\tempdb.mdf C:\....\templog.ldf
model C:\....\model.mdf C:\....\modellog.ldf
and rest of the databases
If your TempDB's have multiple MDF's (like mine have), this script will fail.
However, you can use
WHERE db.database_id > 4
at the end and it will return all databases except system databases.

You can also try this.
select db_name(dbid) dbname, filename from sys.sysaltfiles

Below script can be used to get following information:
1. DB Size Info
2. FileSpaceInfo
3. AutoGrowth
4. Recovery Model
5. Log_reuse_backup information
CREATE TABLE #tempFileInformation
(
DBNAME NVARCHAR(256),
[FILENAME] NVARCHAR(256),
[TYPE] NVARCHAR(120),
FILEGROUPNAME NVARCHAR(120),
FILE_LOCATION NVARCHAR(500),
FILESIZE_MB DECIMAL(10,2),
USEDSPACE_MB DECIMAL(10,2),
FREESPACE_MB DECIMAL(10,2),
AUTOGROW_STATUS NVARCHAR(100)
)
GO
DECLARE #SQL VARCHAR(2000)
SELECT #SQL = '
USE [?]
INSERT INTO #tempFileInformation
SELECT
DBNAME =DB_NAME(),
[FILENAME] =A.NAME,
[TYPE] = A.TYPE_DESC,
FILEGROUPNAME = fg.name,
FILE_LOCATION =a.PHYSICAL_NAME,
FILESIZE_MB = CONVERT(DECIMAL(10,2),A.SIZE/128.0),
USEDSPACE_MB = CONVERT(DECIMAL(10,2),(A.SIZE/128.0 - ((A.SIZE - CAST(FILEPROPERTY(A.NAME,''SPACEUSED'') AS INT))/128.0))),
FREESPACE_MB = CONVERT(DECIMAL(10,2),(A.SIZE/128.0 - CAST(FILEPROPERTY(A.NAME,''SPACEUSED'') AS INT)/128.0)),
AUTOGROW_STATUS = ''BY '' +CASE is_percent_growth when 0 then cast (growth/128 as varchar(10))+ '' MB - ''
when 1 then cast (growth as varchar(10)) + ''% - '' ELSE '''' END
+ CASE MAX_SIZE WHEN 0 THEN '' DISABLED ''
WHEN -1 THEN '' UNRESTRICTED''
ELSE '' RESTRICTED TO '' + CAST(MAX_SIZE/(128*1024) AS VARCHAR(10)) + '' GB '' END
+ CASE IS_PERCENT_GROWTH WHEn 1 then '' [autogrowth by percent]'' else '''' end
from sys.database_files A
left join sys.filegroups fg on a.data_space_id = fg.data_space_id
order by A.type desc,A.name
;
'
--print #sql
EXEC sp_MSforeachdb #SQL
go
SELECT dbSize.*,fg.*,d.log_reuse_wait_desc,d.recovery_model_desc
FROM #tempFileInformation fg
LEFT JOIN sys.databases d on fg.DBNAME = d.name
CROSS APPLY
(
select dbname,
sum(FILESIZE_MB) as [totalDBSize_MB],
sum(FREESPACE_MB) as [DB_Free_Space_Size_MB],
sum(USEDSPACE_MB) as [DB_Used_Space_Size_MB]
from #tempFileInformation
where dbname = fg.dbname
group by dbname
)dbSize
go
DROP TABLE #tempFileInformation

Using this script you can show all the databases name and files used (with exception of system dbs).
select name,physical_name from sys.master_files where database_id > 4

To get around queries which error when multiple data files (e.g. ".ndf" file types) exist, try this version, it replaces the sub-queries with joins.
Here's a version of your query using joins instead of the sub-queries.
Cheers!
SELECT
db.name AS DBName,
db.database_id,
mfr.physical_name AS DataFile,
mfl.physical_name AS LogFile
FROM sys.databases db
JOIN sys.master_files mfr ON db.database_id=mfr.database_id AND mfr.type_desc='ROWS'
JOIN sys.master_files mfl ON db.database_id=mfl.database_id AND mfl.type_desc='LOG'
ORDER BY db.database_id
Sample Results:
(Please note, the single log file is paired with each MDF and NDF for a single database)

This script lists most of what you are looking for and can hopefully be modified to you needs. Note that it is creating a permanent table in there - you might want to change it. It is a subset from a larger script that also summarises backup and job information on various servers.
IF OBJECT_ID('tempdb..#DriveInfo') IS NOT NULL
DROP TABLE #DriveInfo
CREATE TABLE #DriveInfo
(
Drive CHAR(1)
,MBFree INT
)
INSERT INTO #DriveInfo
EXEC master..xp_fixeddrives
IF OBJECT_ID('[dbo].[Tmp_tblDatabaseInfo]', 'U') IS NOT NULL
DROP TABLE [dbo].[Tmp_tblDatabaseInfo]
CREATE TABLE [dbo].[Tmp_tblDatabaseInfo](
[ServerName] [nvarchar](128) NULL
,[DBName] [nvarchar](128) NULL
,[database_id] [int] NULL
,[create_date] datetime NULL
,[CompatibilityLevel] [int] NULL
,[collation_name] [nvarchar](128) NULL
,[state_desc] [nvarchar](60) NULL
,[recovery_model_desc] [nvarchar](60) NULL
,[DataFileLocations] [nvarchar](4000)
,[DataFilesMB] money null
,DataVolumeFreeSpaceMB INT NULL
,[LogFileLocations] [nvarchar](4000)
,[LogFilesMB] money null
,LogVolumeFreeSpaceMB INT NULL
) ON [PRIMARY]
INSERT INTO [dbo].[Tmp_tblDatabaseInfo]
SELECT
##SERVERNAME AS [ServerName]
,d.name AS DBName
,d.database_id
,d.create_date
,d.compatibility_level
,CAST(d.collation_name AS [nvarchar](128)) AS collation_name
,d.[state_desc]
,d.recovery_model_desc
,(select physical_name + ' | ' AS [text()]
from sys.master_files m
WHERE m.type = 0 and m.database_id = d.database_id
ORDER BY file_id
FOR XML PATH ('')) AS DataFileLocations
,(select sum(size) from sys.master_files m WHERE m.type = 0 and m.database_id = d.database_id) AS DataFilesMB
,NULL
,(select physical_name + ' | ' AS [text()]
from sys.master_files m
WHERE m.type = 1 and m.database_id = d.database_id
ORDER BY file_id
FOR XML PATH ('')) AS LogFileLocations
,(select sum(size) from sys.master_files m WHERE m.type = 1 and m.database_id = d.database_id) AS LogFilesMB
,NULL
FROM sys.databases d
WHERE d.database_id > 4 --Exclude basic system databases
UPDATE [dbo].[Tmp_tblDatabaseInfo]
SET DataFileLocations =
CASE WHEN LEN(DataFileLocations) > 4 THEN LEFT(DataFileLocations,LEN(DataFileLocations)-2) ELSE NULL END
,LogFileLocations =
CASE WHEN LEN(LogFileLocations) > 4 THEN LEFT(LogFileLocations,LEN(LogFileLocations)-2) ELSE NULL END
,DataFilesMB =
CASE WHEN DataFilesMB > 0 THEN DataFilesMB * 8 / 1024.0 ELSE NULL END
,LogFilesMB =
CASE WHEN LogFilesMB > 0 THEN LogFilesMB * 8 / 1024.0 ELSE NULL END
,DataVolumeFreeSpaceMB =
(SELECT MBFree FROM #DriveInfo WHERE Drive = LEFT( DataFileLocations,1))
,LogVolumeFreeSpaceMB =
(SELECT MBFree FROM #DriveInfo WHERE Drive = LEFT( LogFileLocations,1))
select * from [dbo].[Tmp_tblDatabaseInfo]

If you rename your Database, MS SQL Server does not rename the underlying files.
Following query gives you the current name of the database and the Logical file name (which might be the original name of the Database when it was created) and also corresponding physical file names.
Note: Un-comment the last line to see only the actual data files
select db.database_id,
db.name "Database Name",
files.name "Logical File Name",
files.physical_name
from sys.master_files files
join sys.databases db on db.database_id = files.database_id
-- and files.type_desc = 'ROWS'
Reference:
https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-master-files-transact-sql?view=sql-server-ver15
https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-databases-transact-sql?view=sql-server-ver15

Using the sp_MSForEachDB stored procedure is an option
EXEC sp_MSForEachDB 'use ? select * from sys.database_files'
Additionally to see just the Full Path name and size information
EXEC sp_MSForEachDB '
USE [?];
SELECT DB_NAME() AS DbName,
physical_name AS FullPath,
name AS FileName,
type_desc,
size/128.0 AS CurrentSizeMB,
size/128.0 - CAST(FILEPROPERTY(name, ''SpaceUsed'') AS INT)/128.0 AS FreeSpaceMB
FROM sys.database_files
WHERE type IN (0,1);
'

just adding my 2 cents .
if specifically looking to find total free space only in Data files or only in Log files in all the databases, we can use "data_space_id" column. 1 is for data files and 0 for log files.
CODE:
Create Table ##temp
(
DatabaseName sysname,
Name sysname,
spacetype sysname,
physical_name nvarchar(500),
size decimal (18,2),
FreeSpace decimal (18,2)
)
Exec sp_msforeachdb '
Use [?];
Insert Into ##temp (DatabaseName, Name,spacetype, physical_name, Size, FreeSpace)
Select DB_NAME() AS [DatabaseName], Name, ***data_space_id*** , physical_name,
Cast(Cast(Round(cast(size as decimal) * 8.0/1024.0,2) as decimal(18,2))/1024 as nvarchar) SizeGB,
Cast(Cast(Round(cast(size as decimal) * 8.0/1024.0,2)/1024 as decimal(18,2)) -
Cast(FILEPROPERTY(name, ''SpaceUsed'') * 8.0/1024.0 as decimal(18,2))/1024 as nvarchar) As FreeSpaceGB
From sys.database_files'
select
databasename
, sum(##temp.FreeSpace)
from
##temp
where
##temp.spacetype = 1
group by
DatabaseName
drop table ##temp

Also you can use this SQL query for retrieving files list :
SELECT d.name AS DatabaseName,
m.name AS LogicalName,
m.physical_name AS PhysicalName,
size AS FileSize
FROM sys.master_files m
INNER JOIN sys.databases d ON(m.database_id = d.database_id)
where d.name = '<Database Name>'
ORDER BY physical_name ;

You can use the below:
SP_HELPDB [Master]
GO

Related

SELECT number of Logical CPU

I have written query that allows me to have an overview of all Azure SQL Database inside an Azure SQL Server; this query needs to be run on master:
DECLARE #StartDate date = DATEADD(day, -30, GETDATE()) -- 14 Days
SELECT
database_name AS DatabaseName,
sysso.edition
,sysso.service_objective
,(SELECT TOP 1 storage_in_megabytes FROM sys.resource_stats AS rs2 WHERE rs2.database_name = rs1.database_name ORDER BY rs2.start_time DESC) AS StorageMB
,CAST(MAX(storage_in_megabytes) / 1024 AS DECIMAL(10, 2)) StorageGB
,MIN(end_time) AS StartTime
,MAX(end_time) AS EndTime
,CAST(AVG(avg_cpu_percent) AS decimal(4,2)) AS Avg_CPU
,MAX(avg_cpu_percent) AS Max_CPU
,(COUNT(database_name) - SUM(CASE WHEN avg_cpu_percent >= 40 THEN 1 ELSE 0 END) * 1.0) / COUNT(database_name) * 100 AS [CPU Fit %]
,CAST(AVG(avg_data_io_percent) AS decimal(4,2)) AS Avg_IO
,MAX(avg_data_io_percent) AS Max_IO
,(COUNT(database_name) - SUM(CASE WHEN avg_data_io_percent >= 40 THEN 1 ELSE 0 END) * 1.0) / COUNT(database_name) * 100 AS [Data IO Fit %]
,CAST(AVG(avg_log_write_percent) AS decimal(4,2)) AS Avg_LogWrite
,MAX(avg_log_write_percent) AS Max_LogWrite
,(COUNT(database_name) - SUM(CASE WHEN avg_log_write_percent >= 40 THEN 1 ELSE 0 END) * 1.0) / COUNT(database_name) * 100 AS [Log Write Fit %]
FROM sys.resource_stats AS rs1
inner join sys.databases dbs on rs1.database_name = dbs.name
INNER JOIN sys.database_service_objectives sysso on sysso.database_id = dbs.database_id
WHERE start_time > #StartDate
GROUP BY database_name, sysso.edition, sysso.service_objective
ORDER BY database_name , sysso.edition, sysso.service_objective
Here the output:
I would like to add to this query how many logical CPU each database has.
I know that there is query that I can run on each database but I want to SELECT how many logical CPU each database has by querying the master database.
Is there a way to grab such information form the sys. tables?
Or dynamic SQL is the only way to go?
EDIT:
#Charlieface suggested to use SELECT cpu_count FROM sys.dm_os_sys_info which is right but if I run it on master I only see the CPU used on master. I need to retrieve the CPUs used for each database.
You add the following subquery:
(SELECT cpu_count FROM sys.dm_os_sys_info)
See the documentation.
Further information for each processor can be got from sys.dm_os_nodes
It seems Azure Managed Instance only returns data for master. So you need to insert it into a temp table or table variable and join on that.
DECLARE #sql nvarchar(max);
SELECT #sql = STRING_AGG(CAST('
SELECT ' + d.id + ', cpu_count FROM ' + QUOTENAME(d.name) + '.sys.dm_os_sys_info
' AS nvarchar(max)), '
UNION ALL
' )
FROM sys.databases;
PRINT #sql; --your friend
DECLARE #tmp TABLE (db_id int PRIMARY KEY, cpu_count int NOT NULL);
INSERT #tmp (db_id, cpu_count)
EXEC sp_executesql #sql;
SELECT ....
cpu.cpu_count
FROM ...
LEFT JOIN #tmp cpu ON cpu.db_id = dbs.id;

T-SQL - Get runduration from a restore job

I'm using the code below to pull 3 columns:
Server Name
Database Name
Date/Time Restore started
Code:
WITH LastRestores
AS
(
SELECT
##SERVERNAME AS [ServerName],
[d].[name] AS [DatabaseName],
CONVERT(VARCHAR, r.restore_date, 100) AS [RestoreDateTime],
RowNum = ROW_NUMBER() OVER (PARTITION BY d.NAME
ORDER BY r.[restore_date] DESC)
FROM
master.sys.databases d
LEFT OUTER JOIN
msdb.dbo.[restorehistory] r ON r.[destination_database_name] = d.NAME
)
SELECT
[ServerName], [DatabaseName], [RestoreDateTime]
FROM
[LastRestores]
WHERE
[RowNum] = 1
AND DatabaseName NOT IN ('master', 'model', 'msdb', 'tempdb')
AND CONVERT(VARCHAR(12), [RestoreDateTime]) = CONVERT(VARCHAR(12), GETDATE())
What I'd like to do is get the RunDuration that is tied in with the msdb..sysjobhistory table. I can't, for the life of me, see how to tie that table in with my code above. I'm sure there is a round about way to get the info I am looking for.
Any suggestions?
Thanks!
You can find the end datetime of a restore in the SQL Server logs. You can use xp_readerrorlog to read the logs. Please note that the format of the message may be different depending on your version. This code works in SQL Server 2012.
CREATE TABLE #t (LogDate DATETIME, ProcessInfo VARCHAR(100), RowVal VARCHAR(512));
INSERT INTO #t
EXEC master.dbo.xp_readerrorlog;
WITH RestoreDate AS (
SELECT
LEFT(REPLACE(RowVal, 'Database was restored: Database: ', ''), CHARINDEX(', creation', REPLACE(RowVal, 'Database was restored: Database: ', '')) - 1) AS DbName,
LogDate
FROM
#t
WHERE
RowVal LIKE 'Database was restored: Database: %'),
LastRestores AS (
SELECT
##SERVERNAME AS [ServerName],
[d].[name] AS [DatabaseName],
CONVERT(VARCHAR, r.restore_date, 100) AS [RestoreDateTime],
RowNum = ROW_NUMBER() OVER (PARTITION BY d.NAME
ORDER BY r.[restore_date] DESC)
FROM
master.sys.databases d
LEFT OUTER JOIN
msdb.dbo.[restorehistory] r ON r.[destination_database_name] = d.NAME)
SELECT
l.[ServerName],
l.[DatabaseName],
l.[RestoreDateTime],
MAX(r.LogDate) AS LogDate,
CONVERT(VARCHAR, MAX(r.LogDate), 100) AS FormattedLogDate
FROM
[LastRestores] l
JOIN
RestoreDate r
ON l.DatabaseName = r.DbName
WHERE
l.[RowNum] = 1
AND l.DatabaseName NOT IN ('master', 'model', 'msdb', 'tempdb')
AND CONVERT(VARCHAR(12), [RestoreDateTime]) = CONVERT(VARCHAR(12), GETDATE())
GROUP BY
l.[ServerName],
l.[DatabaseName],
l.[RestoreDateTime];
DROP TABLE #t;

SQL Server: How to list all CLR functions/procedures/objects for assembly

Question: In SQL Server 2005, how can I list all SQL CLR-functions/procedures that use assembly xy (e.g. MyFirstUdp) ?
For example a function that lists HelloWorld for query parameter MyFirstUdp
CREATE PROCEDURE HelloWorld
AS EXTERNAL NAME MyFirstUdp.[SQL_CLRdll.MySQLclass].HelloWorld
GO
after I ran
CREATE ASSEMBLY MyFirstUdp FROM 'C:\Users\username\Documents\Visual Studio 2005\Projects\SQL_CLRdll\SQL_CLRdll\bin\Debug\SQL_CLRdll.dll
I can list all assemblies and all functions/procedures,
but I seem to be unable to associate the assembly to the functions/procedures...
Check out the sys.assembly_modules view:
select * from sys.assembly_modules
This should list all functions and the assemblies they're defined in. See the Books Online help page about it.
Returns one row for each function,
procedure or trigger that is defined
by a common language runtime (CLR)
assembly.
I use the following SQL:
SELECT so.name AS [ObjectName],
so.[type],
SCHEMA_NAME(so.[schema_id]) AS [SchemaName],
asmbly.name AS [AssemblyName],
asmbly.permission_set_desc,
am.assembly_class,
am.assembly_method
FROM sys.assembly_modules am
INNER JOIN sys.assemblies asmbly
ON asmbly.assembly_id = am.assembly_id
AND asmbly.is_user_defined = 1 -- if using SQL Server 2008 or newer
-- AND asmbly.name NOT LIKE 'Microsoft%' -- if using SQL Server 2005
INNER JOIN sys.objects so
ON so.[object_id] = am.[object_id]
UNION ALL
SELECT at.name AS [ObjectName],
'UDT' AS [type],
SCHEMA_NAME(at.[schema_id]) AS [SchemaName],
asmbly.name AS [AssemblyName],
asmbly.permission_set_desc,
at.assembly_class,
NULL AS [assembly_method]
FROM sys.assembly_types at
INNER JOIN sys.assemblies asmbly
ON asmbly.assembly_id = at.assembly_id
AND asmbly.is_user_defined = 1 -- if using SQL Server 2008 or newer
-- AND asmbly.name NOT LIKE 'Microsoft%' -- if using SQL Server 2005
ORDER BY [AssemblyName], [type], [ObjectName]
Please note:
User-Defined Types (UDTs) are found in: sys.assembly_types
You can only list SQLCLR references that have been used in CREATE { PROCEDURE | FUNCTION | AGGREGATE | TRIGGER | TYPE } statements. You cannot find SQLCLR methods that have not yet been referenced by a CREATE. Meaning, you cannot say: "give me a list of methods in this assembly that I can create T-SQL objects for".
For more info on working with SQLCLR in general, please visit: SQLCLR Info
Here is a generalization of srutzky's query (above) that goes through all DBs on a server using a cursor. Sorry about the formatting, but this is handy if you have to search through 500 DB's you've inherited.
set nocount on
declare #cmd nvarchar(4000)
declare curDBs cursor read_only for
SELECT name FROM MASTER.sys.sysdatabases
declare #NameDB nvarchar(100)
create table #tmpResults (
DatabaseName nvarchar(128)
, ObjectName nvarchar(128)
, ObjectType char(2)
, SchemaName nvarchar(128)
, AssemblyName nvarchar(128)
, PermissionSet nvarchar(60)
, AssemblyClass nvarchar(128)
, AssemblyMethod nvarchar(128));
open curDBs; while (1=1)
begin
fetch next from curDBs into #NameDB
if ##fetch_status <> 0 break
set #cmd = N'
USE [' + #NameDB + N'];
begin try
insert into #tmpResults
SELECT ''' + #NameDB + N''',
so.name AS [ObjectName],
so.[type],
SCHEMA_NAME(so.[schema_id]) AS [SchemaName],
asy.name AS [AssemblyName],
asy.permission_set_desc,
am.assembly_class,
am.assembly_method
FROM sys.assembly_modules am
INNER JOIN sys.assemblies asy
ON asy.assembly_id = am.assembly_id
AND asy.is_user_defined = 1
INNER JOIN sys.objects so
ON so.[object_id] = am.[object_id]
UNION ALL
SELECT ''' + #NameDB + N''',
at.name AS [ObjectName],
''UDT'' AS [type],
SCHEMA_NAME(at.[schema_id]) AS [SchemaName],
asy.name AS [AssemblyName],
asy.permission_set_desc,
at.assembly_class,
NULL AS [assembly_method]
FROM sys.assembly_types at
INNER JOIN sys.assemblies asy
ON asy.assembly_id = at.assembly_id
AND asy.is_user_defined = 1
ORDER BY [AssemblyName], [type], [ObjectName]
print ''' + #NameDB + N' ' + cast(##rowcount as nvarchar) + N'''
end try
begin catch
print ''Error processing ' + #NameDB + '''
end catch
'
--print #cmd
EXEC sp_executesql #cmd
end
close curDBs; deallocate curDBs
select * from #tmpResults
drop table #tmpResults
Here it a script found on sqlhint.com:
SELECT
SCHEMA_NAME(O.schema_id) AS [Schema], O.name,
A.name AS assembly_name, AM.assembly_class,
AM.assembly_method,
A.permission_set_desc,
O.[type_desc]
FROM
sys.assembly_modules AM
INNER JOIN sys.assemblies A ON A.assembly_id = AM.assembly_id
INNER JOIN sys.objects O ON O.object_id = AM.object_id
ORDER BY
A.name, AM.assembly_class
Also, you have the option to see all the places where that CLR object is used.
SELECT
modules.assembly_class AS AssemblyClass,
modules.assembly_method AS MethodName,
obj.type_desc AS MethodType,
files.name AS FilePath,
assemb.name AS AssemblyName,
assemb.clr_name,
assemb.create_date,
assemb.modify_date,
assemb.permission_set_desc
--,*
FROM
sys.assembly_modules AS modules
JOIN sys.assembly_files AS files ON files.assembly_id = modules.assembly_id
JOIN sys.assemblies AS assemb ON assemb.assembly_id = modules.assembly_id
JOIN sys.objects AS obj ON obj.object_id = modules.object_id
Or you can use
SELECT * FROM sys.dm_clr_appdomains;
which returns a list of assemblies and in what database they are stored.

Find an object in SQL Server (cross-database)

If I've been told a table (or proc) name, but not which connected database the object is located in, is there any simple script to search for it? Maybe search somewhere in the System Databases? (I'm using SQL Server 2005)
There is a schema called INFORMATION_SCHEMA schema which contains a set of views on tables from the SYS schema that you can query to get what you want.
A major upside of the INFORMATION_SCHEMA is that the object names are very query friendly and user readable. The downside of the INFORMATION_SCHEMA is that you have to write one query for each type of object.
The Sys schema may seem a little cryptic initially, but it has all the same information (and more) in a single spot.
You'd start with a table called SysObjects (each database has one) that has the names of all objects and their types.
One could search in a database as follows:
Select [name] as ObjectName, Type as ObjectType
From Sys.Objects
Where 1=1
and [Name] like '%YourObjectName%'
Now, if you wanted to restrict this to only search for tables and stored procs, you would do
Select [name] as ObjectName, Type as ObjectType
From Sys.Objects
Where 1=1
and [Name] like '%YourObjectName%'
and Type in ('U', 'P')
If you look up object types, you will find a whole list for views, triggers, etc.
Now, if you want to search for this in each database, you will have to iterate through the databases. You can do one of the following:
If you want to search through each database without any clauses, then use the sp_MSforeachdb as shown in an answer here.
If you only want to search specific databases, use the "USE DBName" and then search command.
You will benefit greatly from having it parameterized in that case. Note that the name of the database you are searching in will have to be replaced in each query (DatabaseOne, DatabaseTwo...). Check this out:
Declare #ObjectName VarChar (100)
Set #ObjectName = '%Customer%'
Select 'DatabaseOne' as DatabaseName, [name] as ObjectName, Type as ObjectType
From DatabaseOne.Sys.Objects
Where 1=1
and [Name] like #ObjectName
and Type in ('U', 'P')
UNION ALL
Select 'DatabaseTwo' as DatabaseName, [name] as ObjectName, Type as ObjectType
From DatabaseTwo.Sys.Objects
Where 1=1
and [Name] like #ObjectName
and Type in ('U', 'P')
UNION ALL
Select 'DatabaseThree' as DatabaseName, [name] as ObjectName, Type as ObjectType
From DatabaseThree.Sys.Objects
Where 1=1
and [Name] like #ObjectName
and Type in ('U', 'P')
sp_MSforeachdb 'select db_name(), * From ?..sysobjects where xtype in (''U'', ''P'') And name = ''ObjectName'''
Instead of 'ObjectName' insert object you are looking for. First column will display name of database where object is located at.
Easiest way is to hit up the information_schemas...
SELECT *
FROM information_schema.Tables
WHERE [Table_Name]='????'
SELECT *
FROM information_schema.Views
WHERE [Table_Name]='????'
SELECT *
FROM information_schema.Routines
WHERE [Routine_Name]='????'
You can achieve this by using the following query:
EXEC sp_msforeachdb
'IF EXISTS
(
SELECT 1
FROM [?].sys.objects
WHERE name LIKE ''OBJECT_TO_SEARCH''
)
SELECT
''?'' AS DB,
name AS Name,
type_desc AS Type
FROM [?].sys.objects
WHERE name LIKE ''OBJECT_TO_SEARCH'''
Just replace OBJECT_TO_SEARCH with the actual object name you are interested in (or part of it, surrounded with %).
More details here: https://peevsvilen.blog/2019/07/30/search-for-an-object-in-sql-server/
You can use sp_MSforeachdb to search all databases.
declare #RETURN_VALUE int
declare #command1 nvarchar(2000)
set #command1 = "Your command goes here"
exec #RETURN_VALUE = sp_MSforeachdb #command1 = #command1
Raj
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
/**********************************************************************
Naziv procedure : sp_rfv_FIND
Ime i prezime autora: Srdjan Nadrljanski
Datum kreiranja : 13.06.2013.
Namena : Traži sql objekat na celom serveru
Tabele :
Ulazni parametri :
Izlazni parametri :
Datum zadnje izmene :
Opis izmene :
exec sp_rfv_FIND 'TUN',''
**********************************************************************/
CREATE PROCEDURE [dbo].[sp_rfv_FIND] ( #SEARCHSTRING VARCHAR(255),
#notcontain Varchar(255)
)
AS
declare #text varchar(1500),#textinit varchar (1500)
set #textinit=
'USE #sifra
insert into ##temp2
select ''#sifra''as dbName,a.[Object Name],a.[Object Type]
from(
SELECT DISTINCT sysobjects.name AS [Object Name] ,
case
when sysobjects.xtype = ''C'' then ''CHECK constraint''
when sysobjects.xtype = ''D'' then ''Default or DEFAULT constraint''
when sysobjects.xtype = ''F'' then ''Foreign Key''
when sysobjects.xtype = ''FN'' then ''Scalar function''
when sysobjects.xtype = ''P'' then ''Stored Procedure''
when sysobjects.xtype = ''PK'' then ''PRIMARY KEY constraint''
when sysobjects.xtype = ''S'' then ''System table''
when sysobjects.xtype = ''TF'' then ''Function''
when sysobjects.xtype = ''TR'' then ''Trigger''
when sysobjects.xtype = ''U'' then ''User table''
when sysobjects.xtype = ''UQ'' then ''UNIQUE constraint''
when sysobjects.xtype = ''V'' then ''View''
when sysobjects.xtype = ''X'' then ''Extended stored procedure''
end as [Object Type]
FROM sysobjects
WHERE
sysobjects.type in (''C'',''D'',''F'',''FN'',''P'',''K'',''S'',''TF'',''TR'',''U'',''V'',''X'')
AND sysobjects.category = 0
AND CHARINDEX(''#SEARCHSTRING'',sysobjects.name)>0
AND ((CHARINDEX(''#notcontain'',sysobjects.name)=0 or
CHARINDEX(''#notcontain'',sysobjects.name)<>0))
)a'
set #textinit=replace(#textinit,'#SEARCHSTRING',#SEARCHSTRING)
set #textinit=replace(#textinit,'#notcontain',#notcontain)
SELECT name AS dbName,cast(null as varchar(255)) as ObjectName,cast(null as varchar(255)) as ObjectType
into ##temp1
from master.dbo.sysdatabases order by name
SELECT * INTO ##temp2 FROM ##temp1 WHERE 1 = 0
declare #sifra VARCHAR(255),#suma int,#brojac int
set #suma=(select count(dbName) from ##temp1)
DECLARE c_k CURSOR LOCAL FAST_FORWARD FOR
SELECT dbName FROM ##temp1 ORDER BY dbName DESC
OPEN c_k
FETCH NEXT FROM c_K INTO #sifra
SET #brojac = 1
WHILE (##fetch_status = 0 ) AND (#brojac <= #suma)
BEGIN
set #text=replace(#textinit,'#sifra',#sifra)
exec (#text)
SET #brojac = #brojac +1
DELETE FROM ##temp1 WHERE dbName = #sifra
FETCH NEXT FROM c_k INTO #sifra
END
close c_k
DEALLOCATE c_k
select * from ##temp2
order by dbName,ObjectType
drop table ##temp2
drop table ##temp1
SELECT NAME AS ObjectName
,schema_name(o.schema_id) AS SchemaName, OBJECT_NAME(o.parent_object_id) as TableName
,type
,o.type_desc
FROM sys.objects o
WHERE o.is_ms_shipped = 0
AND o.NAME LIKE '%UniqueID%'
ORDER BY o.NAME
mayby one little change from the top answer, because DB_NAME() returns always content db of execution. so, for me better like below:
sp_MSforeachdb 'select DB_name(db_id(''?'')) as DB, * From ?..sysobjects where xtype in (''U'', ''P'') And name like ''[_]x[_]%'''
In my case I was looking for tables their names started with _x_
Cheers,
Ondrej
----Option 2
SELECT DISTINCT
o.name,
o.xtype
FROM
syscomments c
INNER JOIN
sysobjects o
ON
c.id=o.id
WHERE
c.TEXT LIKE '%TableName%'
order by
o.name desc,
o.xtype desc
select db_name(), * From sysobjects where xtype in ('U', 'P') And name = 'OBJECT_name'
First column will display name of database where object is located at.

How to get a table storage information

SQL Server Edition: SQL Server 2005 w/ SP3 and 2008
Is there a built-in SQL Server stored procedures that will retrieve following information?
Or a DMV (Dynamic Management View) would be great as well.
I am interested mainly on how to find out FILEGROUP data of a table specifically.
But it'd be better if there was a sproc that will return all of following result.
By the way, is there any documents that shows one-to-one matching of how to retrieve data that SQL Server UI displays?
The system stored procedure sp_help could be a good starting point.
For example:
exec sp_help 'schema.TableName'
This will show you all kinds of goodness:
-- Script to analyze table space usage using the
-- output from the sp_spaceused stored procedure
-- Works with SQL 7.0, 2000, and 2005
set nocount on
print 'Show Size, Space Used, Unused Space, Type, and Name of all database files'
select
[FileSizeMB] =
convert(numeric(10,2),sum(round(a.size/128.,2))),
[UsedSpaceMB] =
convert(numeric(10,2),sum(round(fileproperty( a.name,'SpaceUsed')/128.,2))) ,
[UnusedSpaceMB] =
convert(numeric(10,2),sum(round((a.size-fileproperty( a.name,'SpaceUsed'))/128.,2))) ,
[Type] =
case when a.groupid is null then '' when a.groupid = 0 then 'Log' else 'Data' end,
[DBFileName] = isnull(a.name,'*** Total for all files ***')
from
sysfiles a
group by
groupid,
a.name
with rollup
having
a.groupid is null or
a.name is not null
order by
case when a.groupid is null then 99 when a.groupid = 0 then 0 else 1 end,
a.groupid,
case when a.name is null then 99 else 0 end,
a.name
create table #TABLE_SPACE_WORK
(
TABLE_NAME sysname not null ,
TABLE_ROWS numeric(18,0) not null ,
RESERVED varchar(50) not null ,
DATA varchar(50) not null ,
INDEX_SIZE varchar(50) not null ,
UNUSED varchar(50) not null ,
)
create table #TABLE_SPACE_USED
(
Seq int not null
identity(1,1) primary key clustered,
TABLE_NAME sysname not null ,
TABLE_ROWS numeric(18,0) not null ,
RESERVED varchar(50) not null ,
DATA varchar(50) not null ,
INDEX_SIZE varchar(50) not null ,
UNUSED varchar(50) not null ,
)
create table #TABLE_SPACE
(
Seq int not null
identity(1,1) primary key clustered,
TABLE_NAME SYSNAME not null ,
TABLE_ROWS int not null ,
RESERVED int not null ,
DATA int not null ,
INDEX_SIZE int not null ,
UNUSED int not null ,
USED_MB numeric(18,4) not null,
USED_GB numeric(18,4) not null,
AVERAGE_BYTES_PER_ROW numeric(18,5) null,
AVERAGE_DATA_BYTES_PER_ROW numeric(18,5) null,
AVERAGE_INDEX_BYTES_PER_ROW numeric(18,5) null,
AVERAGE_UNUSED_BYTES_PER_ROW numeric(18,5) null,
)
declare #fetch_status int
declare #proc varchar(200)
select #proc = rtrim(db_name())+'.dbo.sp_spaceused'
declare Cur_Cursor cursor local
for
select
TABLE_NAME =
rtrim(TABLE_SCHEMA)+'.'+rtrim(TABLE_NAME)
from
INFORMATION_SCHEMA.TABLES
where
TABLE_TYPE = 'BASE TABLE'
order by
1
open Cur_Cursor
declare #TABLE_NAME varchar(200)
select #fetch_status = 0
while #fetch_status = 0
begin
fetch next from Cur_Cursor
into
#TABLE_NAME
select #fetch_status = ##fetch_status
if #fetch_status <> 0
begin
continue
end
truncate table #TABLE_SPACE_WORK
insert into #TABLE_SPACE_WORK
(
TABLE_NAME,
TABLE_ROWS,
RESERVED,
DATA,
INDEX_SIZE,
UNUSED
)
exec #proc #objname =
#TABLE_NAME ,#updateusage = 'true'
-- Needed to work with SQL 7
update #TABLE_SPACE_WORK
set
TABLE_NAME = #TABLE_NAME
insert into #TABLE_SPACE_USED
(
TABLE_NAME,
TABLE_ROWS,
RESERVED,
DATA,
INDEX_SIZE,
UNUSED
)
select
TABLE_NAME,
TABLE_ROWS,
RESERVED,
DATA,
INDEX_SIZE,
UNUSED
from
#TABLE_SPACE_WORK
end --While end
close Cur_Cursor
deallocate Cur_Cursor
insert into #TABLE_SPACE
(
TABLE_NAME,
TABLE_ROWS,
RESERVED,
DATA,
INDEX_SIZE,
UNUSED,
USED_MB,
USED_GB,
AVERAGE_BYTES_PER_ROW,
AVERAGE_DATA_BYTES_PER_ROW,
AVERAGE_INDEX_BYTES_PER_ROW,
AVERAGE_UNUSED_BYTES_PER_ROW
)
select
TABLE_NAME,
TABLE_ROWS,
RESERVED,
DATA,
INDEX_SIZE,
UNUSED,
USED_MB =
round(convert(numeric(25,10),RESERVED)/
convert(numeric(25,10),1024),4),
USED_GB =
round(convert(numeric(25,10),RESERVED)/
convert(numeric(25,10),1024*1024),4),
AVERAGE_BYTES_PER_ROW =
case
when TABLE_ROWS <> 0
then round(
(1024.000000*convert(numeric(25,10),RESERVED))/
convert(numeric(25,10),TABLE_ROWS),5)
else null
end,
AVERAGE_DATA_BYTES_PER_ROW =
case
when TABLE_ROWS <> 0
then round(
(1024.000000*convert(numeric(25,10),DATA))/
convert(numeric(25,10),TABLE_ROWS),5)
else null
end,
AVERAGE_INDEX_BYTES_PER_ROW =
case
when TABLE_ROWS <> 0
then round(
(1024.000000*convert(numeric(25,10),INDEX_SIZE))/
convert(numeric(25,10),TABLE_ROWS),5)
else null
end,
AVERAGE_UNUSED_BYTES_PER_ROW =
case
when TABLE_ROWS <> 0
then round(
(1024.000000*convert(numeric(25,10),UNUSED))/
convert(numeric(25,10),TABLE_ROWS),5)
else null
end
from
(
select
TABLE_NAME,
TABLE_ROWS,
RESERVED =
convert(int,rtrim(replace(RESERVED,'KB',''))),
DATA =
convert(int,rtrim(replace(DATA,'KB',''))),
INDEX_SIZE =
convert(int,rtrim(replace(INDEX_SIZE,'KB',''))),
UNUSED =
convert(int,rtrim(replace(UNUSED,'KB','')))
from
#TABLE_SPACE_USED aa
) a
order by
TABLE_NAME
print 'Show results in descending order by size in MB'
select * from #TABLE_SPACE order by USED_MB desc
go
drop table #TABLE_SPACE_WORK
drop table #TABLE_SPACE_USED
drop table #TABLE_SPACE
Found a solution.
It seems like it takes longer to type this out than using UI to find out table FILEGROUP information.
Found through List tables in filegroups:
declare #objectid bigint
set #objectid = object_id('table_name')
exec sp_objectfilegroup #objectid
I became too lazy to type those three lines so ended up creating another stored procedure that takes table name instead.
create procedure spTableFileGroup
#TableName sysname
as
begin
if exists( select 1
from INFORMATION_SCHEMA.TABLES T
where T.TABLE_NAME = #TableName) begin
declare #objectid bigint
set #objectid = object_id(#TableName)
exec sp_objectfilegroup #objectid
end
else begin
print 'There is no table named "' + #TableName + '"'
end
end
GO
Usage
exec spTableFileGroup 'table_name'
GO
Have a look at DBCC showfilestats or sp_spaceused for filegroups.
Found a script at a blog. That lists tables and their sizes.
For a more user friendly (administrative view, you can generate reports using right mouse on the db).
The tables FILEGROUP is determined by it's clustered index. You can use this query to find the filegroup:
SELECT *
FROM
sys.tables AS tbl
INNER JOIN sys.indexes AS idx ON idx.object_id = tbl.object_id and idx.index_id < 2
LEFT OUTER JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = idx.data_space_id
In regard to your second question, I don't think there's any documentation, however, you can use SQL profiler when you view the details in SSMS. This will show you the exact queries.
This might do the trick ->
use Your_database_name
GO
SELECT FG.*, MF.* FROM sys.filegroups FG INNER JOIN sys.master_files
MF on MF.data_space_id = FG.data_space_id WHERE database_id = db_id()

Resources