博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
sp_MSforeachtable简介; 遍历数据库中的所有表运行命令
阅读量:2513 次
发布时间:2019-05-11

本文共 11702 字,大约阅读时间需要 39 分钟。

介绍 (Introduction)

There have always been some undocumented objects in SQL Server that are used internally by Microsoft, but they can be used by anybody that have access to it. One of those objects is a stored procedure called sp_MSforeachtable.

Microsoft内部始终使用SQL Server中一些未记录的对象,但是有权访问它的任何人都可以使用它们。 这些对象之一是称为sp_MSforeachtable的存储过程。

sp_MSforeachtable is a stored procedure that is mostly used to apply a T-SQL command to every table, iteratively, that exists in the current database.

sp_MSforeachtable是一个存储过程,通常用于将T-SQL命令迭代地应用于当前数据库中存在的每个表。

Because official documentation from Microsoft doesn’t exist, the majority of people do not know about the existence of all of these parameters and how this stored procedure can be used to perform more than a simple operation over all the database tables.

由于不存在Microsoft的官方文档,因此大多数人不知道所有这些参数的存在以及如何使用此存储过程对所有数据库表执行简单的操作以外的其他操作。

This is main purpose of this article. To provide as much information as possible for this undocumented SQL Server stored procedure so everybody can take the maximum advantage when use it.

这是本文的主要目的。 为该未记录SQL Server存储过程提供尽可能多的信息,以便每个人都可以在使用它时最大程度地利用它。

典型用法 (Typical usages)

From my experience, I have found in the majority of use cases, people using this stored procedure to:

根据我的经验,我发现在大多数用例中,使用此存储过程的人员可以:

  • perform an unconditional reindex over all tables in the database:

    对数据库中的所有表执行无条件重新索引:
   EXEC sp_MSforeachtable 'DBCC DBREINDEX(''?'')' 
  • truncate all tables in the database:

    截断数据库中的所有表:
   EXEC sp_MSforeachtable 'TRUNCATE TABLE ?' 
  • get the information about the number of records from all tables in the database:

    从数据库的所有表中获取有关记录数的信息:
   EXEC sp_MSforeachtable 'SELECT ''?'' TableName, Count(1) NumRecords FROM ?' 

I think by now you should get the idea on how to use this undocumented stored procedure and also realized that the question mark (?) it is used as the replacement of the table and during the execution it will be replaced by the appropriate table name.

我认为,现在您应该对如何使用此未记录的存储过程有所了解,并且还意识到将问号(?)用作表的替换,并且在执行过程中它将被适当的表名替换。

But the above are only the examples for the typical usage of the sp_MSforeachtable stored procedure. This stored procedure allows more parameters. If only one is passed (as the above examples) it will use by default the @command1 parameter.

但是以上只是sp_MSforeachtable存储过程的典型用法示例。 此存储过程允许更多参数。 如果仅传递一个(如上述示例),则默认情况下将使用@ command1参数。

sp_MSforeachtable参数 (sp_MSforeachtable parameters)

So how to know the rest of the parameters if this is an undocumented stored procedure?

那么,如果这是一个未记录的存储过程,那么如何知道其余参数呢?

We can easily find out the parameters for the sp_MSforeachtable stored procedure by searching for it in the SQL Server Management Studio (SSMS). In SSMS, drill down to “Databases / System Databases / master / Programmability / Stored Procedures / System Stored Procedures” and look for sys.sp_MSforeachtable’s parameters:

通过在SQL Server Management Studio(SSMS)中进行搜索,我们可以轻松找到sp_MSforeachtable存储过程的参数。 在SSMS中,向下钻取至“ 数据库/系统数据库/主数据库/可编程性/存储过程/系统存储过程 ”,然后寻找sys.sp_MSforeachtable的参数:

@command1, @command2, @command3 sp_MSforeachtable stored procedure requires at least one command to be executed (@command1) but it allows up to 3 commands to be executed. Note that it will start to execute first the @command1 and then @command2 and @command3 by the last and this for each table.

@ command1,@ command2,@ command3 sp_MSforeachtable存储过程要求至少执行一个命令(@ command1),但最多允许执行3个命令。 请注意,它将首先开始执行@ command1,然后在最后执行@ command2和@ command3,并对每个表执行此操作。

@precommand Use this parameter to provide a command to be executed before the @command1. It is useful to set variable environments or perform any kind of initialization.

@precommand使用此参数可提供要在@ command1之前执行的命令。 设置可变环境或执行任何类型的初始化都是有用的。

@postcommand Use this parameter to provide a command to be executed after all the commands being executed successfully. It is useful for control and cleanup processes.

@postcommand使用此参数可提供所有命令成功执行后要执行的命令。 这对于控制和清理过程很有用。

@replacechar By default, a table is represented by the question mark (?) character. This parameter allows you to change this character.
@replacechar默认情况下,表由问号(?)字符表示。 此参数允许您更改此字符。

@whereand By default, sp_MSforeachtable is applied to all user tables in the database. Use this parameter to filter the tables that you want to work with. On the next section, I will explain how you can filter the tables.

@whereand默认情况下, sp_MSforeachtable应用于数据库中的所有用户表。 使用此参数可以筛选要使用的表。 在下一节中,我将解释如何过滤表。

sp_MSforeachtable定义 (sp_MSforeachtable definition)

For a better understanding of the sp_MSforeachtable stored procedure let see it’s code. To get this stored procedure code, in SSMS right-click on the stored procedure name and choose the Modify option.

为了更好地了解sp_MSforeachtable存储过程,请查看其代码。 要获取此存储过程代码,请在SSMS中右键单击存储过程名称,然后选择“ 修改”选项。

This will create a new query window with the respective stored procedure code:

这将使用相应的存储过程代码创建一个新的查询窗口:

 USE [master]GO/****** Object:  StoredProcedure [sys].[sp_MSforeachtable]    Script Date: 8/18/2017 8:47:44 AM ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER OFFGO ALTER proc [sys].[sp_MSforeachtable]	@command1 nvarchar(2000), @replacechar nchar(1) = N'?', @command2 nvarchar(2000) = null,   @command3 nvarchar(2000) = null, @whereand nvarchar(2000) = null,	@precommand nvarchar(2000) = null, @postcommand nvarchar(2000) = nullas	/* This proc returns one or more rows for each table (optionally, matching @where), with each table defaulting to its own result set */	/* @precommand and @postcommand may be used to force a single result set via a temp table. */ 	/* Preprocessor won't replace within quotes so have to use str(). */	declare @mscat nvarchar(12)	select @mscat = ltrim(str(convert(int, 0x0002))) 	if (@precommand is not null)		exec(@precommand) 	/* Create the select */   exec(N'declare hCForEachTable cursor global for select ''['' + REPLACE(schema_name(syso.schema_id), N'']'', N'']]'') + '']'' + ''.'' + ''['' + REPLACE(object_name(o.id), N'']'', N'']]'') + '']'' from dbo.sysobjects o join sys.all_objects syso on o.id = syso.object_id '         + N' where OBJECTPROPERTY(o.id, N''IsUserTable'') = 1 ' + N' and o.category & ' + @mscat + N' = 0 '         + @whereand)	declare @retval int	select @retval = @@error	if (@retval = 0)		exec @retval = sys.sp_MSforeach_worker @command1, @replacechar, @command2, @command3, 0 	if (@retval = 0 and @postcommand is not null)		exec(@postcommand) 	return @retval 

You can see now the full code of this undocumented stored procedure. In the header, you can confirm the existence of the parameters referred in the previous section. You can also see that this procedure uses a Cursor (N’declare hCForEachTable cursor global) to go through all user tables (where OBJECTPROPERTY(o.id, N”IsUserTable”) = 1) in the current database. Plus, at the end it concatenates the select statement with whatever we pass in the @whereand parameter. Looking at the code, it joins dbo.sysobjects with sys.all_objects (from dbo.sysobjects o join sys.all_objects syso) so we just need to work from here.

现在,您可以看到此未记录的存储过程的完整代码。 在标题中,您可以确认上一节中提到的参数是否存在。 您还可以看到此过程使用游标( N'declare hCForEachTable cursor global )遍历当前数据库中的所有用户表( 其中OBJECTPROPERTY(o.id,N” IsUserTable”)= 1 )。 另外,最后,它将select语句与我们在@whereand参数中传递的内容连接起来 。 查看代码,它将dbo.sysobjects与sys.all_objects连接( 来自dbo.sysobjects或join sys.all_objects syso ),所以我们只需要从这里开始工作。

完整的例子 (Full example)

Now that we have the sp_MSforeachtable stored procedure definition let’s practice with an example so we can try to cover all parameters.

现在我们有了sp_MSforeachtable存储过程的定义,让我们以一个示例进行练习,以便我们尝试覆盖所有参数。

The database has a HumanResources schema so I am using this database for this example.

数据库具有HumanResources模式,因此在此示例中我将使用此数据库。

Imagine that our Human Resources department requested us to check the database growth because they are facing some kind of disk free space issue and want to determine which table or tables are growing more than expected.

想象一下,我们的人力资源部门要求我们检查数据库的增长,因为他们面临某种磁盘可用空间问题,并且想要确定哪些表增长超过了预期。

As can be seen in the solution I am presenting below, the @whereand parameter is used to filter only the tables that belong to HumanResources schema. As explained before, the code that is passed in this parameter is concatenated to the SELECT query that will be used by the cursor definition in the sp_MSforeachtable stored procedure so we are using it to filter the HumanResources schema.

从下面提供的解决方案中可以看出, @ whereand参数仅用于过滤属于HumanResources模式的表。 如前所述,在此参数中传递的代码被连接到SELECT查询,该查询将由sp_MSforeachtable存储过程中的游标定义使用,因此我们正在使用它来筛选HumanResources模式。

I am using the @precommand parameter to create a global temporary table called ##Statistics to store the information that will be need to be shown at the end. This global temporary table will be dropped at the end as it can be seen in the @postcommand parameter after returning the required data (the SELECT statement just before the DROP statement).

我正在使用@precommand参数创建名为## Statistics的全局临时表,以存储将需要在末尾显示的信息。 返回所需数据(在DROP语句之前的SELECT语句)之后,可以在@postcommand参数中看到该全局临时表的末尾。

So, for each table in that belongs to HumanResources schema it will be applied the code in @command1 and @command2 parameters. As explained before, these parameters are used sequentially, i.e. it will first execute @command1 and after this one finish it will execute @command2. If @command3 parameter exists, it will be executed after @command2 finish. And this is why I have an INSERT statement in @command1 parameter and an UPDATE statement in @command2 parameter, since it is expected that the row already exists when @command2 is executed so we will not insert again the row but update it instead.

因此,对于属于HumanResources模式的每个表,都将应用@ command1@ command2参数中的代码。 如前所述,这些参数是按顺序使用的,即它将首先执行@ command1,完成后将执行@ command2。 如果@ command3参数存在,它将在@ command2完成后执行。 这就是为什么我在@ command1参数中有INSERT语句,而在@ command2参数中有UPDATE语句的原因,因为在执行@ command2时预期该行已经存在,所以我们不会再次插入该行,而是对其进行更新。

Follow is the code that you can test. Feel free to change it to perform other kind of tests that can be useful for you:

遵循的是您可以测试的代码。 随时更改它以执行对您有用的其他类型的测试:

 USE AdventureworksGO exec sp_MSforeachtable @precommand = 'CREATE TABLE ##Statistics 		(TableName varchar(128) NOT NULL, 		NumOfRows int,		SpaceUsed float)',@command1='INSERT INTO ##Statistics (TableName, NumOfRows)		SELECT ''?'' TableName, COUNT(1) NumOfRows FROM ?',@command2='UPDATE S	SET s.SpaceUsed = g.SizeKB	FROM ##Statistics s	INNER JOIN (SELECT p.object_id TableID, sum(a.total_pages) * 8192 / 1024.0 SizeKB			FROM sys.partitions p 			INNER JOIN sys.allocation_units a on p.partition_id = a.container_id			GROUP BY p.object_id) g		ON OBJECT_ID(s.TableName) = g.TableID	WHERE s.TableName = ''?''',@postcommand = 'SELECT TableName, NumOfRows, SpaceUsed			FROM ##Statistics			ORDER BY SpaceUsed DESC, NumOfRows DESC;		DROP TABLE ##Statistics',@whereand='AND schema_name(schema_id) = ''HumanResources''' 

For the example above you will get a similar output as below:

对于上面的示例,您将获得类似以下的输出:

NOTE: The solution could be simpler by using the but I preferred the above solution to better show how to work with more than a command parameter.

注意:通过使用 ,解决方案可能更简单,但是我更喜欢上面的解决方案,以更好地展示如何使用多个命令参数。

免责声明 (Disclaimer)

Microsoft does not recommend the usage of the undocumented objects because they do not offer any support for these kinds of objects as they may be changed or dropped in future SQL Server releases without any previous warning.

Microsoft不建议使用未记录的对象,因为它们不提供对此类对象的任何支持,因为它们可能会在将来SQL Server版本中更改或删除而没有任何事先警告。

From my own experience, these undocumented objects have been not experienced any changes in the past so if you want to use them, remember to perform tests with those objects in any new SQL Server version that will be released in the future to assure the correct operation of your code.

根据我自己的经验,这些未记录的对象在过去从未经历过任何更改,因此,如果要使用它们,请记住对这些对象进行测试,这些对象将在将来发布的任何新SQL Server版本中执行,以确保正确的操作您的代码。

翻译自:

转载地址:http://fwswd.baihongyu.com/

你可能感兴趣的文章
冲刺Noip2017模拟赛3 解题报告——五十岚芒果酱
查看>>
并查集
查看>>
sessionStorage
查看>>
代码示例_进程
查看>>
Java中关键词之this,super的使用
查看>>
学习进度
查看>>
“此人不存在”
查看>>
github.com加速节点
查看>>
解密zend-PHP凤凰源码程序
查看>>
python3 序列分片记录
查看>>
Atitit.git的存储结构and 追踪
查看>>
atitit 读书与获取知识资料的attilax的总结.docx
查看>>
B站 React教程笔记day2(3)React-Redux
查看>>
找了一个api管理工具
查看>>
Part 2 - Fundamentals(4-10)
查看>>
使用Postmark测试后端存储性能
查看>>
NSTextView 文字链接的定制化
查看>>
第五天站立会议内容
查看>>
(转))iOS App上架AppStore 会遇到的坑
查看>>
解决vmware与主机无法连通的问题
查看>>