Database 查询所有表的不同计数时Tempdb Full
原始问题 我创建了一个自定义脚本,用于将数据从远程SQL server检索到办公室的本地副本中。我在脚本中遇到了一些问题,其中选定的表插入了两次某些数据,从而创建了重复项。我知道所有数据库中的所有表都不应该有重复项 这个问题让我产生了一种妄想,其他表可能在历史上有过这个问题,因此我想验证一下 解决方案 我创建了一个SQL脚本,用于将所有列的计数和不同计数插入到服务器上所有数据库(不包括4个系统数据库)的表中: 表变量@AllTables使用带有信息的sp_msforeachdb_SCHEMA.TABLES列出所有数据库中的所有表(共16537个表)。表游标用于存储所有非系统项,然后我使用动态SQL进行计数和不同的计数,该计数存储在另一个表变量@ResultsTable中 此解决方案的问题 当我运行此查询时,它将运行大约3分钟,然后抛出一个错误,指出tempdb主文件组已满: 我是我自己的DBA,我习惯于设置我的SQL server实例,我的tempdb设置了8 x 3GB mdf/ndf文件(服务器有8个核心): 这些文件在“常规”属性下显示为有23997MB可用空间 我的问题Database 查询所有表的不同计数时Tempdb Full,database,sql-server-2012,tempdb,Database,Sql Server 2012,Tempdb,原始问题 我创建了一个自定义脚本,用于将数据从远程SQL server检索到办公室的本地副本中。我在脚本中遇到了一些问题,其中选定的表插入了两次某些数据,从而创建了重复项。我知道所有数据库中的所有表都不应该有重复项 这个问题让我产生了一种妄想,其他表可能在历史上有过这个问题,因此我想验证一下 解决方案 我创建了一个SQL脚本,用于将所有列的计数和不同计数插入到服务器上所有数据库(不包括4个系统数据库)的表中: 表变量@AllTables使用带有信息的sp_msforeachdb_SCHEMA.T
在添加TEMPDB文件之前,应该始终考虑争用。添加7个额外的TempDb文件并没有真正的帮助
如果我有大约24GB的tempdb可用空间,为什么这是相对的 简单查询是否耗尽了tempdb空间 不,不应该。但是,您确定您没有处理大量的数据,或者您没有在SQL上运行其他进程吗?游标、临时表甚至表变量广泛使用TempDb。检查哪个对象占用更多的TempDb空间:SELECT
SUM (user_object_reserved_page_count)*8 as usr_obj_kb,
SUM (internal_object_reserved_page_count)*8 as internal_obj_kb,
SUM (version_store_reserved_page_count)*8 as version_store_kb,
SUM (unallocated_extent_page_count)*8 as freespace_kb,
SUM (mixed_extent_page_count)*8 as mixedextent_kb
FROM sys.dm_db_file_space_usage
因此,如果您的用户和内部对象更多,那么这显然意味着由于游标和SQL Server内部使用(例如:中间表、散列联接、散列聚合等),您的TempDb空间较低
是否有更好/更有效的方法来获取计数和区分
所有数据库中所有表的计数
您可以使用下面的代码获取所有数据库中所有表的计数
DECLARE @Stats TABLE (DBNAME VARCHAR(40), NAME varchar(200), Rows INT)
INSERT INTO @Stats
EXECUTE sp_MSForEachDB
'USE ?; SELECT DB_NAME()AS DBName,
sysobjects.Name
, sysindexes.Rows
FROM
sysobjects
INNER JOIN sysindexes
ON sysobjects.id = sysindexes.id
WHERE
type = ''U''
AND sysindexes.IndId < 2'
SELECT * FROM @Stats
同样,您可以使用下面的查询在所有数据库的所有表中使用distinct
DECLARE @ServerStatsDistinct TABLE (DatabaseName varchar(200), TableName varchar(200), RowsCount INT)
INSERT INTO @ServerStatsDistinct
exec sp_msforeachdb @command1='
use #;
if ''#'' NOT IN (''master'', ''model'', ''msdb'', ''tempdb'',''ReportServer'')
begin
print ''#''
exec sp_MSforeachtable @command1=''
SELECT ''''#'''' AS DATABASENAME, ''''?'''' AS TABLENAME, COUNT(*) FROM (
SELECT DISTINCT *
FROM ?
) a ;
''
end
', @replacechar = '#'
SELECT * FROM @ServerStatsDistinct
正在处理多少数据?如果对具有许多不同值的不同数据进行区分,则所有这些值最终都会出现在临时工作表中。解决这一问题的办法并非微不足道。您需要分块处理该表。感谢回复usr。您是指子查询:从“+@TableFullName”中选择DISTINCT*?是否已将其放入tempdb中?显然,它处理数千个表,因此如果它缓存所有这些表(我本以为每次循环都会清除缓存?),那么它将有数百GB的数据。子查询在循环的每次迭代中都不会从缓存中删除吗?我会在上面搜索一下。你在说什么缓存?每次查询结束时,tempdb的使用结束。一定有一些大的查询。我承认我对查询缓存的了解非常有限,但是为什么SQL server会为循环中运行的每个子查询缓存所有的表(以及整个表)?谢谢回答Anuj。虽然我并不自称是专家,但我对tempdb的了解足以让我了解争用,并且我已经按照微软的指导为8个处理器内核设置了8个tempdb文件。在这种情况下,问题是由SELECT DISTINCT导致的,SELECT DISTINCT每次都在tempdb中缓存。由于我正在对服务器实例中的每个数据库执行此查询,因此任何tempdb重新配置都不足以完成此操作。但是,我的另一个经验领域是VB,因此我将编写一个VBA程序来实现这一点,并在这里发布答案。我还想指出,您提供的用于检查哪些对象用于消耗tempdb空间的代码非常有用,谢谢您(我将在稍后提供的答案中使用此代码)。但是,您提供的用于获取每个表中的行的代码没有太大帮助,因为(1)它没有为我提供不同的计数,这是我的问题的一个要求,(2)它基于统计数据,没有计数(*)那么准确。@quarcheck我已经用更新的查询库编辑了我的答案,以继续支持Anuj。最后,事实证明,使用您在原始答案中给我的查询帮助我找到了问题的根源。我真的很喜欢你独特的查询实际上,它比我自己的要简洁得多。我不知道我可以将sp_msforeachdb执行到这样的表中,或者您可以将sp_msforeachtable嵌套到sp_msforeachdb中。非常聪明!用光标救了我!最后,问题是一个大表(唯一一个大于24GB的表)接近结果的开始,这导致tempdb抛出错误。在对结果进行排序后,我发现了这个问题。在我排除此表后,它目前正在运行最后几个数据库,因此再次感谢您的帮助。自编辑以来,我已将您的答案标记为已接受答案,因为您已成功回答了我的两个问题。:)
DECLARE @ServerStats TABLE (DatabaseName varchar(200), TableName varchar(200), RowsCount INT)
INSERT INTO @ServerStats
exec sp_msforeachdb @command1='
use #;
if ''#'' NOT IN (''master'', ''model'', ''msdb'', ''tempdb'',''ReportServer'')
begin
print ''#''
exec sp_MSforeachtable @command1=''
SELECT ''''#'''' AS DATABASENAME, ''''?'''' AS TABLENAME, COUNT(*) FROM ? ;
''
end
', @replacechar = '#'
SELECT * FROM @ServerStats
DECLARE @ServerStatsDistinct TABLE (DatabaseName varchar(200), TableName varchar(200), RowsCount INT)
INSERT INTO @ServerStatsDistinct
exec sp_msforeachdb @command1='
use #;
if ''#'' NOT IN (''master'', ''model'', ''msdb'', ''tempdb'',''ReportServer'')
begin
print ''#''
exec sp_MSforeachtable @command1=''
SELECT ''''#'''' AS DATABASENAME, ''''?'''' AS TABLENAME, COUNT(*) FROM (
SELECT DISTINCT *
FROM ?
) a ;
''
end
', @replacechar = '#'
SELECT * FROM @ServerStatsDistinct