SQL Server 游标运用:查看所有数据库所有表大小信息(Sizes of All Tables in All Database)
原文:SQL Server 游标运用:查看所有数据库所有表大小信息(Sizes of All Tables in All Database)
一.本文所涉及的内容(Contents)
二.背景(Contexts)
之前写了篇关于:SQL Server 游标运用:查看一个数据库所有表大小信息(Sizes of All Tables in a Database)的文章,它罗列出某个数据所有表的信息,这些信息包括:表的记录数、数据记录占用空间、索引占用空间、没使用的空间等(如Figure1所示),现在我来讲述如何获取整个数据库实例中所有数据库所有表的信息(如Figure2所示)。
(Figure1:某数据库所有表信息)
(Figure2:所有数据库所有表信息)
三.实现代码(SQL Codes)
下面内容讲述了在实现Figure2过程中遇到的一些问题,如果你对这些问题不感兴趣可以直接看最后实现的SQL脚本。下面讲述了4种实现方法:
1. 游标 + 系统存储过程sp_MSForEachDB,实现脚本为Script3;
2. 封装sp_MSforeachtable + sys.databases,实现脚本为Script4和Script5;
3. 系统存储过程sp_MSForEachDB + sp_MSforeachtable,实现脚本为Script6;
4. 扩展sp_MSforeachdb + sp_MSforeachtable,实现脚本为Script7;
(一) 我们在SQL Server 游标运用:查看一个数据库所有表大小信息(Sizes of All Tables in a Database)的SQL脚本中进行改进,结合sp_MSForEachDB系统存储过程进行实现:
1) 既然有了获取某个数据库所有表信息的脚本,那就可以在外层再套使用sp_MSForEachDB系统存储过程,下面的Script1脚本可以获取到所有数据库的所有表的信息,效果如Figure3所示:
- --Script1:
- --查看所有数据库所有表信息
- EXEC sp_MSForEachDB 'USE [?];
- DECLARE @tablespaceinfo TABLE (
- nameinfo VARCHAR(50),
- rowsinfo INT,
- reserved VARCHAR(20),
- datainfo VARCHAR(20),
- index_size VARCHAR(20),
- unused VARCHAR(20)
- )
- DECLARE @tablename VARCHAR(255);
- DECLARE Info_cursor CURSOR FOR
- SELECT ''[''+[name]+'']'' FROM sys.tables WHERE TYPE=''U'';
- OPEN Info_cursor
- FETCH NEXT FROM Info_cursor INTO @tablename
- WHILE @@FETCH_STATUS = 0
- BEGIN
- INSERT INTO @tablespaceinfo EXEC sp_spaceused @tablename
- FETCH NEXT FROM Info_cursor
- INTO @tablename
- END
- CLOSE Info_cursor
- DEALLOCATE Info_cursor
- SELECT * FROM @tablespaceinfo
- ORDER BY Cast(Replace(reserved,''KB'','''') AS INT) DESC'
(Figure3:所有数据库所有表)
2) 上图Figure3有两个缺点,第一是返回的数据太分散,没有统一表进行管理,第二是需要过滤master、model、msdb和tempdb等系统数据库,因为我们完全不关心系统数据库,下面的SQL脚本展示在使用sp_msforeachdb的时候如何排除某个数据库,效果如Figure4所示:
- --sp_msforeachdb排除某个数据库
- EXEC sp_msforeachdb 'IF ''?'' <> ''tempdb'' print ''?'''
(Figure4:sp_msforeachdb排除某个数据库)
3) 下面的SQL脚本展示在使用sp_msforeachdb的时候如何排除多个数据库,效果如Figure5所示:
- --sp_msforeachdb排除多个数据库
- EXEC sp_msforeachdb 'IF ''?'' not in(''tempdb'',''master'',''model'',''msdb'') print ''?'''
(Figure5:sp_msforeachdb排除多个数据库)
4) 把上面的SQL脚本运用到之前获取某个数据库表信息的SQL脚本中,但是执行的过程中出现了Figure6的错误信息:
- --Script2:
- --查看所有数据库所有表信息
- IF NOT EXISTS (SELECT * FROM [tempdb].sys.objects WHERE object_id = OBJECT_ID(N'[tempdb].[dbo].[tablespaceinfo]') AND type in (N'U'))
- BEGIN
- CREATE TABLE [tempdb].[dbo].[tablespaceinfo](
- [nameinfo] [varchar](255) NULL,
- [rowsinfo] [int] NULL,
- [reserved] [varchar](20) NULL,
- [datainfo] [varchar](20) NULL,
- [index_size] [varchar](20) NULL,
- [unused] [varchar](20) NULL
- ) ON [PRIMARY]
- END
- ELSE
- TRUNCATE TABLE tempdb.dbo.tablespaceinfo
- EXEC sp_MSForEachDB 'USE [?];
- --IF ''?'' not in(''tempdb'',''master'',''model'',''msdb'')
- IF ''?'' in(''AdventureWorksLT2008R2'')
- BEGIN
- print ''?''
- DECLARE @tablename VARCHAR(255);
- DECLARE Info_cursor CURSOR FOR
- SELECT ''[''+[name]+'']'' FROM ?.sys.tables WHERE TYPE=''U'';
- OPEN Info_cursor
- FETCH NEXT FROM Info_cursor INTO @tablename
- WHILE @@FETCH_STATUS = 0
- BEGIN
- INSERT INTO tempdb.dbo.tablespaceinfo EXEC ?.dbo.sp_spaceused @tablename
- FETCH NEXT FROM Info_cursor
- INTO @tablename
- END
- CLOSE Info_cursor
- DEALLOCATE Info_cursor
- END
- '
- --返回表
- SELECT * FROM tempdb.dbo.tablespaceinfo
- --ORDER BY Cast(Replace(reserved,'KB','') AS INT) DESC
- ORDER BY nameinfo
(Figure6:错误信息)
5) 经过一番查找,最后发现是因为AdventureWorksLT2008R2数据库的安全中的架构是SalesLT,不是默认的dbo,所以报了Figure6的错误信息,但是如果使用sp_MSforeachtable,那就不用理会框架的问题。
(Figure7:SalesLT架构名)
只要我们在表名称前面加入正确的架构名,那就可以正确执行了,如Figure8所示:
- --使用正确的架构名
- AdventureWorksLT2008R2.dbo.sp_spaceused 'SalesLT.Address'
(Figure8:正确的架构名)
6) 经过上面经验的总结,关于所有数据库所有表的信息的SQL脚本就水到渠成了,下面就是全部的SQL脚本,注意过滤的方式可以写成:IF ''?'' like(''A%'') ,执行的效果如Figure2所示:
- --Script3:
- -- =============================================
- -- Author: <听风吹雨>
- -- Create date: <2013.05.03>
- -- Description: <查看所有数据库所有表信息>
- -- Blog: <http://www.cnblogs.com/gaizai/>
- -- =============================================
- --定义临时表
- IF NOT EXISTS (SELECT * FROM [tempdb].sys.objects WHERE object_id = OBJECT_ID(N'[tempdb].[dbo].[tablespaceinfo]') AND type in (N'U'))
- BEGIN
- CREATE TABLE [tempdb].[dbo].[tablespaceinfo](
- [db_name] [sysname] NULL,
- [table_name] [sysname] NULL,
- [rows] [bigint] NULL,
- [reserved] [varchar](100) NULL,
- [data] [varchar](100) NULL,
- [index_size] [varchar](100) NULL,
- [unused] [varchar](100) NULL
- ) ON [PRIMARY]
- END
- ELSE
- TRUNCATE TABLE tempdb.dbo.tablespaceinfo
- DECLARE @SQL NVARCHAR(MAX)
- SET @SQL = COALESCE(@SQL,'') + '
- USE [?];
- --屏蔽掉系统数据库
- IF ''?'' not in(''tempdb'',''master'',''model'',''msdb'')
- --IF ''?'' like(''A%'')
- BEGIN
- PRINT ''?''
- DECLARE @schemas_name VARCHAR(255);
- DECLARE @table_name VARCHAR(255);
- DECLARE Info_cursor CURSOR FOR
- --获取schemas_name和table_name
- SELECT b.name AS schemas_name,''[''+a.[name]+'']'' AS table_name FROM ?.sys.tables AS a
- LEFT JOIN ?.sys.schemas AS b
- ON a.schema_id = b.schema_id
- WHERE TYPE=''U''
- OPEN Info_cursor
- FETCH NEXT FROM Info_cursor INTO @schemas_name,@table_name
- WHILE @@FETCH_STATUS = 0
- BEGIN
- --把表信息插入到临时表
- SET @table_name = ''[''+@schemas_name+'']''+''.''+@table_name
- INSERT INTO tempdb.dbo.tablespaceinfo([table_name],[rows],[reserved],[data],[index_size],[unused])
- EXEC ?.dbo.sp_spaceused @table_name
- --更新数据库名称
- UPDATE tempdb.dbo.tablespaceinfo SET [db_name] = ''?'' WHERE [db_name] IS NULL
- FETCH NEXT FROM Info_cursor INTO @schemas_name,@table_name
- END
- CLOSE Info_cursor
- DEALLOCATE Info_cursor
- END
- '
- --循环所有数据库
- PRINT @SQL
- EXEC sp_MSForEachDB @SQL
- --返回临时表数据
- SELECT * FROM tempdb.dbo.tablespaceinfo
- ORDER BY [db_name],Cast(Replace(reserved,'KB','') AS INT) DESC
- --ORDER BY [db_name],[table_name]
- DROP TABLE [tempdb].[dbo].[tablespaceinfo]
(二) 还有没其他方式可以实现Figure2的效果呢?你可以考虑使用sp_MSforeachtable的方式实现,先使用存储过程sp_spaceused_db简单封装sp_MSforeachtable,它简单实现获取某个数据库的所有表,再使用拼凑生成批量的INSERT和UPDATE语句生成表信息数据,Script9与Script10需要分开执行,执行的效果如Figure2所示:
- --Script4:
- USE [tempdb]
- GO
- IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[sp_spaceused_db]') AND type in (N'P', N'PC'))
- DROP PROCEDURE [dbo].[sp_spaceused_db]
- GO
- -- =============================================
- -- Author: <听风吹雨>
- -- Create date: <2013.05.06>
- -- Description: <封装sp_MSforeachtable>
- -- Blog: <http://www.cnblogs.com/gaizai/>
- -- =============================================
- CREATE PROCEDURE [dbo].[sp_spaceused_db]
- @db_name nvarchar(776) = null
- AS
- BEGIN
- DECLARE @SQL NVARCHAR(MAX)
- SELECT @SQL = COALESCE(@SQL,'') + '
- EXEC ['+@db_name+'].dbo.sp_MSforeachtable @command1="sp_spaceused ''?''"'
- PRINT(@SQL)
- EXECUTE(@SQL)
- END
- --Script5:
- -- =============================================
- -- Author: <听风吹雨>
- -- Create date: <2013.05.06>
- -- Description: <查看所有数据库所有表信息>
- -- Blog: <http://www.cnblogs.com/gaizai/>
- -- =============================================
- CREATE TABLE [tempdb].[dbo].[tablespaceinfo](
- [db_name] [sysname] NULL,
- [table_name] [sysname] NULL,
- [rows] [bigint] NULL,
- [reserved] [varchar](100) NULL,
- [data] [varchar](100) NULL,
- [index_size] [varchar](100) NULL,
- [unused] [varchar](100) NULL
- )
- DECLARE @SQL NVARCHAR(MAX)
- SELECT @SQL = COALESCE(@SQL,'') + '
- INSERT INTO [tempdb].[dbo].[tablespaceinfo]([table_name],[rows],[reserved],[data],[index_size],[unused])
- EXEC [tempdb].dbo.sp_spaceused_db ' + QUOTENAME(name,'''') + '
- UPDATE [tempdb].[dbo].[tablespaceinfo] SET [db_name] = ' + QUOTENAME(name,'''') + '
- WHERE [db_name] IS NULL'
- FROM sys.databases WHERE database_id >4
- PRINT(@SQL)
- EXECUTE(@SQL)
- SELECT * FROM [tempdb].[dbo].[tablespaceinfo]
- ORDER BY [db_name],Cast(Replace(reserved,'KB','') AS INT) DESC
- DROP TABLE [tempdb].[dbo].[tablespaceinfo]
(三) 如果你想使用sp_MSForEachDB与sp_MSforeachtable(sp_MSforeach_worker、sp_MStablespace)结合的方式实现Figure2效果,刚开始测试的时候发现这两个存储过程在解释“?”的时候会出现歧义,SQL无法理解它是指数据库还是表,难道微软会做那么愚蠢的事情?后来查看了这两个存储过程的SQL脚本,发现是有办法解决上面问题的。
- --Script6:
- -- =============================================
- -- Author: <听风吹雨>
- -- Create date: <2013.05.08>
- -- Description: <查看所有数据库所有表信息>
- -- Blog: <http://www.cnblogs.com/gaizai/>
- -- =============================================
- IF NOT EXISTS (SELECT * FROM [tempdb].sys.objects WHERE object_id = OBJECT_ID(N'[tempdb].[dbo].[tablespaceinfo]') AND type in (N'U'))
- BEGIN
- CREATE TABLE [tempdb].[dbo].[tablespaceinfo](
- [db_name] [sysname] NULL,
- [table_name] [sysname] NULL,
- [rows] [bigint] NULL,
- [reserved] [varchar](100) NULL,
- [data] [varchar](100) NULL,
- [index_size] [varchar](100) NULL,
- [unused] [varchar](100) NULL
- ) ON [PRIMARY]
- END
- ELSE
- TRUNCATE TABLE tempdb.dbo.tablespaceinfo
- DECLARE @SQL NVARCHAR(MAX)
- SELECT @SQL = COALESCE(@SQL,'') + '
- USE [?];
- --屏蔽掉系统数据库
- IF ''?'' not in(''tempdb'',''master'',''model'',''msdb'')
- BEGIN
- --插入表信息
- INSERT INTO tempdb.dbo.tablespaceinfo([table_name],[rows],[reserved],[data],[index_size],[unused])
- EXEC [?].sys.sp_MSforeachtable @command1="sp_spaceused N''$''",@replacechar=N''$''
- --更新数据库名称
- UPDATE tempdb.dbo.tablespaceinfo SET [db_name] = ''?'' WHERE [db_name] IS NULL
- END'
- PRINT (@SQL)
- --所有数据库
- EXEC sp_MSforeachdb @command1="print '?'",@command2=@SQL, @replacechar=N'?'
- --返回临时表数据
- SELECT * FROM tempdb.dbo.tablespaceinfo
- ORDER BY [db_name],Cast(Replace(reserved,'KB','') AS INT) DESC
- DROP TABLE [tempdb].[dbo].[tablespaceinfo]
(四) 上面的Script6脚本过滤数据的方式比较麻烦,所以我对sp_MSforeachdb系统存储过程进行了一些修改,生成一个新的存储过程sp_MSforeachdb_Filter,详情请查看:SQL Server 游标运用:查看一个数据库所有表大小信息(Sizes of All Tables in a Database),在创建了存储过程sp_MSforeachdb_Filter的情况下执行下面的SQL脚本,你可以随意修改@whereand参数来满足你的过滤条件,非常方便。
- --Script7:
- -- =============================================
- -- Author: <听风吹雨>
- -- Create date: <2013.05.08>
- -- Description: <查看所有数据库所有表信息>
- -- Blog: <http://www.cnblogs.com/gaizai/>
- -- =============================================
- IF NOT EXISTS (SELECT * FROM [tempdb].sys.objects WHERE object_id = OBJECT_ID(N'[tempdb].[dbo].[tablespaceinfo]') AND type in (N'U'))
- BEGIN
- CREATE TABLE [tempdb].[dbo].[tablespaceinfo](
- [db_name] [sysname] NULL,
- [table_name] [sysname] NULL,
- [rows] [bigint] NULL,
- [reserved] [varchar](100) NULL,
- [data] [varchar](100) NULL,
- [index_size] [varchar](100) NULL,
- [unused] [varchar](100) NULL
- ) ON [PRIMARY]
- END
- ELSE
- TRUNCATE TABLE tempdb.dbo.tablespaceinfo
- DECLARE @SQL NVARCHAR(MAX)
- SELECT @SQL = COALESCE(@SQL,'') + '
- --插入表信息
- INSERT INTO tempdb.dbo.tablespaceinfo([table_name],[rows],[reserved],[data],[index_size],[unused])
- EXEC [?].sys.sp_MSforeachtable @command1="sp_spaceused N''$''",@replacechar=N''$''
- --更新数据库名称
- UPDATE tempdb.dbo.tablespaceinfo SET [db_name] = ''?'' WHERE [db_name] IS NULL'
- PRINT (@SQL)
- ----过滤数据库
- --EXEC [sp_MSforeachdb_Filter] @command1="print '?'",@command2=@SQL, @replacechar=N'?',
- --@whereand=" and [name] not in('tempdb','master','model','msdb') "
- --过滤数据库
- EXEC [sp_MSforeachdb_Filter] @command1="print '?'",@command2=@SQL, @replacechar=N'?',
- @whereand=" and [dbid] > 4 "
- --返回临时表数据
- SELECT * FROM tempdb.dbo.tablespaceinfo
- ORDER BY [db_name],Cast(Replace(reserved,'KB','') AS INT) DESC
- DROP TABLE [tempdb].[dbo].[tablespaceinfo]
四.参考文献(References)
与存储过程sp_MSforeachdb类似的存储过程sp_MSforeachdb
How to get information about all databases without a loop
SQL Server 游标运用:查看一个数据库所有表大小信息(Sizes of All Tables in a Database)
SQL Server 游标运用:查看所有数据库所有表大小信息(Sizes of All Tables in All Database)的更多相关文章
- SQL Server 游标运用:查看一个数据库所有表大小信息(Sizes of All Tables in a Database)
原文:SQL Server 游标运用:查看一个数据库所有表大小信息(Sizes of All Tables in a Database) 一.本文所涉及的内容(Contents) 本文所涉及的内容(C ...
- SQL Server中怎么查看每个数据库的日志大小,以及怎么确定数据库的日志文件,怎么用语句收缩日志文件
一,找到每个数据库的日志文件大小 SQL Server:查看SQL日志文件大小命令:dbcc sqlperf(logspace) DBA 日常管理工作中,很重要一项工作就是监视数据库文件大小,及日志文 ...
- SQL Server 游标运用:查看数据库所有表大小信息
一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 实现代码(SQL Codes) 方法一:运用游标 方法二:运用系统存储过程 方法三:拼接SQL ...
- 通过 SQL Server 视图访问另一个数据库服务器表的方法
今天项目经理跑过来对我大吼大叫说什么之前安排让我做一大堆接口为什么没做,我直接火了,之前明明没有这个事情…… 不过事情还要解决,好在两个项目都是用的sqlserver,可以通过跨数据库视图来快速解决问 ...
- SQL Server和MySql获取当前数据库每个表的列数
Sql server:(连接数据库后,点击当前数据库再新建查询) select count(c.name),o.name from syscolumns c left join sysobjects ...
- 如何隐藏掉SQL Server中自带系统数据库,数据表,存储过程等显示文件,只显示用户的数据库,数据表等文件
企业管理器了,----> 编辑该数据库的注册属性--->“常规”属性页下面-->“显示系统数据库和系统对象”的选项去掉
- SQL SERVER 性能优化二: 数据库初始值大小及增长方式设置
数据库增长方式主要有两种,按百分比自动增长和按固定大小自动增长,设置初始大小和增长方式需谨慎. 初始大小就是建库的大小,设小了,容易造成磁盘碎片,频繁增长也会影响IO响应.设大了,也不行,设大了,每次 ...
- SQL Server 游标运用:鼠标轨迹字符串分割
一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 游标模板(Cursor Template) 鼠标轨迹字符串分割SQL脚本实现(SQL Code ...
- sql server 中隐藏掉无关数据库
先贴上我实际测试的效果 方法一: Problem I have a SQL Server instance that has hundreds of databases. Navigating th ...
随机推荐
- thinkphp中如何实现无限级分类?
thinkphp中如何实现无限级分类? 一.总结 1.数据表设计+递归算法 二.php实现无限级分类实例总结 1.数据库数据如下: 2.任务需求:给一个id,求自己和所有父亲. 3.实现代码如下:th ...
- 下载的pod链接失效,build diff: /../Podfile.lock: No such file or directory解决办法
build diff: /../Podfile.lock: No such file or directory 1.终端进入文件路径,执行pod install 2.在工程设置中的Build Phas ...
- METHODS OF AND APPARATUS FOR USING TEXTURES IN GRAPHICS PROCESSING SYSTEMS
BACKGROUND The technology described herein relates to methods of and apparatus for using and handlin ...
- solr 7.x 查询及高亮
查询时的api分为两种一种是万能的set,还有一种是setxxxquery @Test public void search2() throws Exception{ HttpSolrClient s ...
- Java、JVM、JRE、JDK等组件的理解
.java ⇒(javac) .classs ⇒ (类加载器)转换后的 .class 文件 ⇒ (解释器)可执行代码 ⇒ (JIT 编译器)⇒ 机器码 0. 虚拟机 Java 有它的虚拟机:Java ...
- Android Studio官方文档: 如何在你的设备上运行你的程序
在实体设备上运行您的应用 设置您的设备,如下所示: 使用一根 USB 电缆将您的设备连接到您的开发机器. 如果您是在 Windows 上开发,可能需要为您的设备安装相应的 USB 驱动程序.如需帮助安 ...
- error: openssl/md5.h: No such file or directory
出现:error: openssl/md5.h: No such file or directory 原因是openssl-devel没有安装,运行: yum install libssl-dev 就 ...
- 集装箱set相关算法
set_union 算法set_union可构造S1.S2的并集.此集合内含S1或S2内的每个元素. S1.S2及其并集都是以排序区间表示.返回值是一个迭代器.指向输出区间的尾端. 因为S1和S ...
- 用Ruby实现的论坛灌水工具:CC98 Post Machine
介绍 ZJU 的校网论坛 CC98 比较活跃.论坛只对校内网开放,而且账号跟学生绑定,每个学生注册的账号数量有限.『十大』是 CC98 的经典页面:基于关注的人数(回帖的用户数而不是回帖的数量)用算法 ...
- Hadoop和RDBMS的混合系统介绍
现在大数据概念被时常提起,社会各界对其关注度越来越高.往往越是火热的东西,人们越容易忽略它的本质.在 slides 中,我首先按照自己的理解,简单的理顺数据处理领域的发展历程.之后,落脚点是两个比较有 ...