-- 外键约束信息
;WITH
FK AS(
SELECT
foreign_schema_name = SCH.name,
foreign_name = FK.name,
FK.is_disabled,
delete_action = FK.delete_referential_action_desc,
update_action = FK.update_referential_action_desc,
constraint_column_id = FKC.constraint_column_id,
FKC.parent_object_id,
FKC.parent_column_id,
FKC.referenced_object_id,
FKC.referenced_column_id
FROM sys.foreign_keysFK
INNER JOIN sys.foreign_key_columnsFKC
ON FK.object_id = FKC.constraint_object_id
INNER JOIN sys.schemasSCH
ON FK.schema_id = SCH.schema_id
),
TB AS(
SELECT
TB.object_id,
schema_name = SCH.name,
table_name = TB.name,
column_id = C.column_id,
column_name = C.name
FROM sys.tablesTB WITH(NOLOCK)
INNER JOIN sys.columnsC WITH(NOLOCK)
ON TB.object_id = C.object_id
INNER JOIN sys.schemas SCH WITH(NOLOCK)
ON TB.schema_id = SCH.schema_id
WHERE TB.is_ms_shipped = 0 -- 此条件表示仅查询不是由内部 SQL Server 组件创建对象
)
SELECT
FK.foreign_schema_name,
FK.foreign_name,
FK.is_disabled,
FK.delete_action,
FK.update_action,
FK.constraint_column_id,
parent_table_schema_name = TBP.schema_name,
parent_table_name = TBP.table_name,
parent_table_column_name = TBP.column_name,
referenced_table_schema_name = TBR.schema_name,
referenced_table_name = TBR.table_name,
referenced_table_column_name = TBR.column_name
FROM FK
INNER JOIN TB TBP
ON FK.parent_object_id = TBP.object_id
AND FK.parent_column_id = TBP.column_id
INNER JOIN TB TBR
ON FK.referenced_object_id = TBR.object_id
AND FK.referenced_column_id = TBR.column_id
ORDER BY foreign_schema_name, parent_table_schema_name, parent_table_name, constraint_column_id
----对象依赖关系
;WITH
DEP AS(
SELECT DISTINCT
object_id,
referenced_object_id = referenced_major_id
FROM sys.sql_dependenciesD
WHERE class IN(0, 1)
),
DEP_TREE AS(
SELECT
object_id,
level = 0,
path = CONVERT(varchar(8000),
RIGHT(10000 + ROW_NUMBER() OVER(ORDER BY object_id), 4))
FROM DEP A
WHERE NOT EXISTS(
SELECT * FROM DEP
WHERE referenced_object_id = A.object_id)
UNION ALL
SELECT
object_id = A.referenced_object_id,
level = B.level + 1,
path = CONVERT(varchar(8000),
B.path +
RIGHT(10000 + ROW_NUMBER() OVER(ORDER BY A.referenced_object_id), 4))
FROM DEP A, DEP_TREE B
WHERE A.object_id = B.object_id
AND A.object_id <> A.referenced_object_id
),
DEP_INFO AS(
SELECT
schema_name = SCH.name,
object_name = O.name,
object_type = O.type_desc,
DEP.level,
DEP.path
FROM DEP_TREE DEP
INNER JOIN sys.objectsO
ON DEP.object_id = O.object_id
INNER JOIN sys.schemas SCH
ON O.schema_id = SCH.schema_id
)
SELECT
object_name = REPLICATE(N' ', level * 2)
+ N'|- '
+ QUOTENAME(schema_name) + N'.' + QUOTENAME(object_name),
object_type,
level
FROM DEP_INFO
ORDER BY path
----表空间信息
;WITH
TB AS(
SELECT
TB.object_id,
schema_name = SCH.name,
table_name = TB.name
FROM sys.tablesTB
INNER JOIN sys.schemasSCH
ON TB.schema_id = SCH.schema_id
WHERE is_ms_shipped = 0 -- 此条件表示仅查询不是由内部 SQL Server 组件创建对象
),
PS AS(
-- 此部分计算表空间的信息
SELECT
object_id,
reserved_pages = SUM(reserved_page_count),
used_pages = SUM(used_page_count),
pages = SUM(
CASE
WHEN index_id > 1 THEN lob_used_page_count + row_overflow_used_page_count
ELSE in_row_data_page_count + lob_used_page_count + row_overflow_used_page_count
END),
row_count = SUM (
CASE
WHEN index_id < 2 THEN row_count
ELSE 0
END)
FROM sys.dm_db_partition_stats PS
GROUP BY object_id
),
ITPS AS(
-- 此部分计算包含 XML INDEX 和 FULLTEXT INDEXE 的空间信息(如果有的话)
SELECT
object_id = ITB.parent_id,
reserved_pages = SUM(reserved_page_count),
used_pages = SUM(used_page_count)
FROMsys.dm_db_partition_statsP
INNER JOIN sys.internal_tables ITB
ON P.object_id = ITB.object_id
WHERE ITB.internal_type IN(202, 204)
GROUP BY ITB.parent_id
),
SIZE AS(
-- 此部分合并所有的空间信息
SELECT
PS.object_id,
reserved_pages = PS.reserved_pages + ISNULL(ITPS.reserved_pages, 0),
used_pages = PS.used_pages + ISNULL(ITPS.used_pages, 0),
PS.pages,
PS.row_count
FROM PS
LEFT JOIN ITPS
ON PS.object_id = ITPS.object_id
)
-- 显示最终的空间统计结果
-- 在前面的统计中,空间统计以页为单位, 8K/页,最终的统计将页数*8,得到KB为单位的空间大小
SELECT
TB.schema_name,
TB.table_name,
SIZE.row_count,
reserved = SIZE.reserved_pages * 8,
data = SIZE.pages * 8,
index_size = CASE
WHEN SIZE.used_pages > SIZE.pages
THEN SIZE.used_pages - SIZE.pages
ELSE 0
END * 8,
unused = CASE
WHEN SIZE.reserved_pages > SIZE.used_pages
THEN SIZE.reserved_pages - SIZE.used_pages
ELSE 0
END * 8
FROM TB
INNER JOIN SIZE
ON TB.object_id = SIZE.object_id
ORDER BY schema_name, table_name
-------所有表、索引视图和Services Broker消息队列的空间信息
;WITH
OBJB AS(
SELECT
schema_id,
object_id,
object_name = name,
object_type = type_desc
FROM sys.objects
WHERE type IN('U ','S ','V ','IT')
UNION ALL
-- 对于 Services Broker 消息队列,应使用 sys.internal_tables 中的 object_id 与 sys.dm_db_partition_stats 关联
SELECT
ITB.schema_id,
ITB.object_id,
object_name = O.name,
type_desc = O.type_desc
FROM sys.objects O
INNER JOIN sys.internal_tables ITB
ON O.object_id = ITB.parent_id
WHERE O.type = 'SQ'
AND ITB.internal_type = 201
),
OBJ AS(
SELECT
OBJB.object_id,
OBJB.object_type,
schema_name = SCH.name,
OBJB.object_name
FROM OBJB
INNER JOIN sys.schemas SCH
ON OBJB.schema_id = SCH.schema_id
),
PS AS(
-- 此部分计算表空间的信息
SELECT
object_id,
reserved_pages = SUM(reserved_page_count),
used_pages = SUM(used_page_count),
pages = SUM(
CASE
WHEN index_id > 1 THEN lob_used_page_count + row_overflow_used_page_count
ELSE in_row_data_page_count + lob_used_page_count + row_overflow_used_page_count
END),
row_count = SUM (
CASE
WHEN index_id < 2 THEN row_count
ELSE 0
END)
FROM sys.dm_db_partition_stats PS
GROUP BY object_id
),
ITPS AS(
-- 此部分计算包含 XML INDEX 和 FULLTEXT INDEXE 的空间信息(如果有的话)
SELECT
object_id = ITB.parent_id,
reserved_pages = SUM(reserved_page_count),
used_pages = SUM(used_page_count)
FROM sys.dm_db_partition_stats P
INNER JOIN sys.internal_tables ITB
ON P.object_id = ITB.object_id
WHERE ITB.internal_type IN(202, 204)
GROUP BY ITB.parent_id
),
SIZE AS(
-- 此部分合并所有的空间信息
SELECT
PS.object_id,
reserved_pages = PS.reserved_pages + ISNULL(ITPS.reserved_pages, 0),
used_pages = PS.used_pages + ISNULL(ITPS.used_pages, 0),
PS.pages,
PS.row_count
FROM PS
LEFT JOIN ITPS
ON PS.object_id = ITPS.object_id
)
-- 显示最终的空间统计结果
-- 在前面的统计中,空间统计以页为单位, 8K/页,最终的统计将页数*8,得到KB为单位的空间大小
SELECT
OBJ.object_type,
OBJ.schema_name,
OBJ.object_name,
SIZE.row_count,
reserved = SIZE.reserved_pages * 8,
data = SIZE.pages * 8,
index_size = CASE
WHEN SIZE.used_pages > SIZE.pages
THEN SIZE.used_pages - SIZE.pages
ELSE 0
END * 8,
unused = CASE
WHEN SIZE.reserved_pages > SIZE.used_pages
THEN SIZE.reserved_pages - SIZE.used_pages
ELSE 0
END * 8
FROM OBJ
INNER JOIN SIZE
ON OBJ.object_id = SIZE.object_id
ORDER BY object_type, schema_name, object_name
---数据库空间信息
----单个数据库空间信息
;WITH
DB AS(
-- 此部分查询数据文件和日志文件空间信息
SELECT
datafile_size = SUM(
CASE
WHEN type = 1 THEN 0
ELSE size
END),
logfile_size = SUM(
CASE
WHEN type = 1 THEN size
ELSE 0
END),
file_size = SUM(size)
FROM sys.database_files
),
DATA AS(
-- 此部分查询数据库中对象的空间使用信息
SELECT
reserved_pages = SUM(AU.total_pages),
used_pages = SUM(AU.used_pages),
pages = SUM(
CASE
-- xml index nodes 和 fulltext catalog map 只应包含在索引部分
WHEN ITB.internal_type IN (202,204) THEN 0
WHEN AU.type <> 1 THEN AU.used_pages
WHEN P.index_id < 2 THEN AU.data_pages
Else 0
END)
FROM sys.partitionsP
INNER JOIN sys.allocation_units AU
ON P.partition_id = AU.container_id
LEFT JOIN sys.internal_tables ITB
ON P.object_id = ITB.object_id
),
SIZE AS(
SELECT
database_space = CONVERT(decimal(15, 2),
DB.file_size * 8 / 1024.),
unallocated_space = CONVERT(decimal(15, 2),
CASE
WHEN DB.datafile_size >= DATA.reserved_pages
THEN (DB.datafile_size - DATA.reserved_pages) * 8 / 1024.
ELSE 0
END),
reserved_space = CONVERT(decimal(15, 2),
DATA.reserved_pages * 8 / 1024),
datafile_size = CONVERT(decimal(15, 2),
DB.datafile_size * 8 / 1024.),
logfile_size = CONVERT(decimal(15, 2),
DB.logfile_size * 8 / 1024.),
data_size = CONVERT(decimal(15, 2),
DATA.pages * 8 / 1024),
index_size = CONVERT(decimal(15, 2),
(DATA.used_pages - DATA.pages) * 8 / 1024),
unused_size = CONVERT(decimal(15, 2),
(DATA.reserved_pages - DATA.used_pages) * 8 / 1024)
FROM DB, DATA
)
SELECT
database_name = DB_NAME(),
*
FROM SIZE
-----当前实例所有数据库空间信息
IF OBJECT_ID(N'tempdb..#database_size') IS NOT NULL
DROP TABLE #database_size
CREATE TABLE #database_size(
database_name sysname,
database_space decimal(15, 2),
unallocated_space decimal(15, 2),
reserved_space decimal(15, 2),
datafile_size decimal(15, 2),
logfile_size decimal(15, 2),
data_size decimal(15, 2),
index_size decimal(15, 2),
unused_size decimal(15, 2)
)
DECLARE
@sql nvarchar(4000)
SELECT
@sql = N'
USE [?]
RAISERROR(N''calculate size on database "?"'', 10, 1) WITH NOWAIT
;WITH
DB AS(
-- 此部分查询数据文件和日志文件空间信息
SELECT
datafile_size = SUM(
CASE
WHEN type = 1 THEN 0
ELSE size
END),
logfile_size = SUM(
CASE
WHEN type = 1 THEN size
ELSE 0
END),
file_size = SUM(size)
FROM sys.database_files
),
DATA AS(
-- 此部分查询数据库中对象的空间使用信息
SELECT
reserved_pages = SUM(AU.total_pages),
used_pages = SUM(AU.used_pages),
pages = SUM(
CASE
-- xml index nodes 和 fulltext catalog map 只应包含在索引部分
WHEN ITB.internal_type IN (202,204) THEN 0
WHEN AU.type <> 1 THEN AU.used_pages
WHEN P.index_id < 2 THEN AU.data_pages
Else 0
END)
FROM sys.partitions P
INNER JOIN sys.allocation_units AU
ON P.partition_id = AU.container_id
LEFT JOIN sys.internal_tables ITB
ON P.object_id = ITB.object_id
),
SIZE AS(
SELECT
database_space = CONVERT(decimal(15, 2),
DB.file_size * 8 / 1024.),
unallocated_space = CONVERT(decimal(15, 2),
CASE
WHEN DB.datafile_size >= DATA.reserved_pages
THEN (DB.datafile_size - DATA.reserved_pages) * 8 / 1024.
ELSE 0
END),
reserved_space = CONVERT(decimal(15, 2),
DATA.reserved_pages * 8 / 1024),
datafile_size = CONVERT(decimal(15, 2),
DB.datafile_size * 8 / 1024.),
logfile_size = CONVERT(decimal(15, 2),
DB.logfile_size * 8 / 1024.),
data_size = CONVERT(decimal(15, 2),
DATA.pages * 8 / 1024),
index_size = CONVERT(decimal(15, 2),
(DATA.used_pages - DATA.pages) * 8 / 1024),
unused_size = CONVERT(decimal(15, 2),
(DATA.reserved_pages - DATA.used_pages) * 8 / 1024)
FROM DB, DATA
)
INSERT #database_size
SELECT
database_name = DB_NAME(),
*
FROM SIZE
'
EXEC sp_MSforeachdb
@command1 = @sql
SELECT * FROM #database_size
ORDER BY database_name
-----磁盘空间信息
-- 默认查询硬盘驱动器
EXEC master.dbo.xp_fixeddrives
-- 查询移动设备(例如U盘)
EXEC master.dbo.xp_fixeddrives 2
-- 查询大量存储设备(CD-ROM,DVD等)
EXEC master.dbo.xp_fixeddrives 3
-- 查询硬盘驱动器
EXEC master.dbo.xp_fixeddrives 4
-- 打开 xp_cmdshell 选项
EXEC sp_configure 'show advanced options', 1
RECONFIGURE
EXEC sp_configure 'xp_cmdshell', 1
RECONFIGURE
GO
-- 使用 msinfo32 查询磁盘空间信息
DECLARE
@temp_file nvarchar(250),
@s nvarchar(4000)
-- 通过 msinfo32 将磁盘信息存储到文件中
SELECT
@temp_file = N'c:\'
+ CONVERT(nvarchar(36), NEWID())
+ N'.nfo',
@s = N'start /wait msinfo32.exe /nfo '
+ QUOTENAME(@temp_file, N'"')
+ N' /categories +ComponentsStorage-ComponentsStorageDisks-ComponentsStorageSCSI-ComponentsStorageIDE'
EXEC master.dbo.xp_cmdshell @s, NO_OUTPUT
-- 从文件中获取磁盘信息
DECLARE
@xml xml
SELECT
@s = N'
SELECT
@xml = CONVERT(xml, T.c)
FROM OPENROWSET(BULK N' + QUOTENAME(@temp_file, N'''')
+ N', SINGLE_BLOB) T(c)'
EXEC sp_executesql @s, N'@xml xml OUTPUT', @xml OUTPUT
-- 删除磁盘信息文件
SELECT
@s = N'DEL '
+ QUOTENAME(@temp_file, N'"')
EXEC master.dbo.xp_cmdshell @s, NO_OUTPUT
-- 显示磁盘信息
SELECT
Item = T.c.value(N'(项目)[1]', 'nvarchar(500)'),
Value = T.c.value(N'(数值)[1]', 'nvarchar(500)')
FROM @xml.nodes(N'/MsInfo
/Category[@name="系统摘要"]
/Category[@name="组件"]
/Category[@name="存储"]
/Category[@name="驱动器"]
/Data') T(c)