原始问题
我创建了一个自定义脚本,用于将远程 SQL 服务器中的数据检索到我们办公室的本地副本中。我在脚本中遇到了一些问题,其中选定的表插入了两次数据,从而产生了重复项。我知道所有数据库中的所有表都不应该重复。
这个问题让我怀疑其他表在历史上可能有这个问题,因此我想验证一下。
解决方案
我创建了一个 SQL 脚本,将所有列的计数和不同计数插入到我们服务器上所有数据库(不包括 4 个系统数据库)的表中:
DECLARE @TableFullName AS NVARCHAR(MAX)
DECLARE @SQLQuery AS NVARCHAR(MAX)
DECLARE @TableHasDuplicates AS BIT
DECLARE @TempTableRowCount AS INT
DECLARE @ResultsTable TABLE ([CompleteTableName] NVARCHAR(200), [CountAll] INT, [CountDistinct] INT)
DECLARE @CountAll INT
DECLARE @CountDistinct INT
SET NOCOUNT ON
DECLARE @AllTables TABLE ([CompleteTableName] NVARCHAR(200))
INSERT INTO @AllTables ([CompleteTableName])
EXEC sp_msforeachdb 'SELECT ''['' + [TABLE_CATALOG] + ''].['' + [TABLE_SCHEMA] + ''].['' + [TABLE_NAME] + '']'' FROM [?].INFORMATION_SCHEMA.TABLES'
SET NOCOUNT OFF;
DECLARE [table_cursor] CURSOR FOR
(SELECT *
FROM @AllTables
WHERE [CompleteTableName] NOT LIKE '%master%' AND [CompleteTableName] NOT LIKE '%msdb%' AND [CompleteTableName] NOT LIKE '%tempdb%' AND [CompleteTableName] NOT LIKE '%model%');
OPEN [table_cursor]
PRINT N'There were ' + CAST(@CountAll AS NVARCHAR(10)) + ' tables with potential duplicate data'
FETCH NEXT FROM [table_cursor]
INTO @TableFullName
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQLQuery = 'SELECT @CntAll = COUNT(*) FROM ' + @TableFullName + ' SELECT @CntDistinct = COUNT(*) FROM (SELECT DISTINCT * FROM ' + @TableFullName + ') AS [sq] IF @CntAll > @CntDistinct SELECT @BitResult=1 ELSE SELECT @BitResult=0';
EXEC sp_executesql @SQLQuery, N'@BitResult BIT OUTPUT, @CntAll INT OUTPUT, @CntDistinct INT OUTPUT', @BitResult = @TableHasDuplicates OUTPUT, @CntAll = @CountAll OUTPUT, @CntDistinct = @CountDistinct OUTPUT;
IF @TableHasDuplicates = 1
BEGIN
INSERT INTO @ResultsTable ([CompleteTableName], [CountAll], [CountDistinct])
SELECT @TableFullName, @CountAll, @CountDistinct
END;
FETCH NEXT FROM [table_cursor]
INTO @TableFullName
END
CLOSE [table_cursor];
DEALLOCATE [table_cursor];
SELECT *
FROM @ResultsTable
它如何工作的概述是表变量@AllTables 使用 sp_msforeachdb 和 INFORMATION_SCHEMA.TABLES 列出所有数据库中的所有表(有 16537 个表)。表游标用于存储所有非系统条目,然后我使用动态 SQL 进行计数和不同计数,这些计数存储在另一个表变量 @ResultsTable 中。
此解决方案的问题
当我运行这个查询时,它将运行大约 3 分钟,然后抛出一个错误,指出 tempdb PRIMARY 文件组已满:
我是我自己的 DBA,我使用Brent Ozar 的指南来设置我的 SQL 服务器实例,我的 tempdb 设置了 8 个 3GB mdf/ndf 文件(服务器有 8 个内核):
这些文件在“常规”属性下显示为 23997MB。
我的问题
- 如果我有大约 24GB 的 tempdb 可用空间,为什么这个相对简单的查询会用完 tempdb 空间?
- 是否有更好/更有效的方法来获取所有数据库中所有表的计数和不同计数?