SQL Server:搜索所有表以获取GUID - 内存不足

时间:2015-02-27 12:10:13

标签: sql sql-server tsql sql-server-2012

我需要从数据库中清除一些数据。我编写了一个查询来搜索所有表中的特定GUID。

我拥有的数据库有大约400个表和2000个uniqueidentifier列。

运行查询后,我收到错误:

An error occurred while executing batch. Error message is: Exception of type 'System.OutOfMemoryException' was thrown.

我正在使用的查询:

DECLARE @begin INT = 1
      , @end INT
      , @table VARCHAR(250)
      , @column VARCHAR(250)
      , @sql NVARCHAR(MAX)
      , @uniqueID nvarchar(100) = 'XXX'

SELECT @end = COUNT(COLUMN_NAME) from INFORMATION_SCHEMA.Columns INNER JOIN INFORMATION_SCHEMA.Tables ON INFORMATION_SCHEMA.Columns.TABLE_NAME = INFORMATION_SCHEMA.Tables.TABLE_NAME AND INFORMATION_SCHEMA.Tables.TABLE_TYPE = 'BASE TABLE' WHERE DATA_TYPE = 'uniqueidentifier'

WHILE @begin <= @end

BEGIN

;WITH ColumnID AS   (
    SELECT  ROW_NUMBER() OVER (ORDER BY c.TABLE_NAME, c.COLUMN_NAME) AS ID
            , c.TABLE_SCHEMA
            , c.TABLE_NAME
            , c.COLUMN_NAME
    FROM    INFORMATION_SCHEMA.Columns c
            INNER JOIN INFORMATION_SCHEMA.Tables t ON c.TABLE_NAME = t.TABLE_NAME AND t.TABLE_TYPE = 'BASE TABLE'
    WHERE DATA_TYPE = 'uniqueidentifier'
    )

SELECT @table = TABLE_NAME, @column = COLUMN_NAME FROM ColumnID WHERE ID = @begin

SET @sql = 'SELECT ''' + @table + ''' AS ''Table Name'', ' + @column + ' AS ''Column Name'' FROM ' + @table + ' WHERE ' + @column + ' = ''' + @uniqueID + '''' 

EXECUTE sp_executesql @sql

SET @begin = @begin + 1

END

问题1:

我该如何解决这个问题?

System.OutOfMemory错误是由于将过多的结果集返回给网格以供SSMS处理。这是客户端错误,而不是SQL Server。使用文件时一切正常(右键单击命令窗格,结果到 - &gt;文件)

问题2:

如何更改查询以获取一个包含表名和列名的表。

IF OBJECT_ID(N'tempdb..#_Results', 'U') IS NOT NULL DROP TABLE #_Results;

CREATE TABLE #_results (table_name  sysname, column_name sysname)

DECLARE @begin INT = 1, @end INT, @table VARCHAR(250), @column VARCHAR(250), @sql NVARCHAR(MAX), @uniqueID nvarchar(100) = 'XXX'

SELECT @end = COUNT(COLUMN_NAME) from INFORMATION_SCHEMA.Columns INNER JOIN INFORMATION_SCHEMA.Tables ON INFORMATION_SCHEMA.Columns.TABLE_NAME = INFORMATION_SCHEMA.Tables.TABLE_NAME AND INFORMATION_SCHEMA.Tables.TABLE_TYPE = 'BASE TABLE' WHERE DATA_TYPE = 'uniqueidentifier'

WHILE @begin <= @end
BEGIN

;WITH ColumnID AS   (
    SELECT  ROW_NUMBER() OVER (ORDER BY c.TABLE_NAME, c.COLUMN_NAME) AS ID
            , c.TABLE_SCHEMA
            , c.TABLE_NAME
            , c.COLUMN_NAME
    FROM    INFORMATION_SCHEMA.Columns c
            INNER JOIN INFORMATION_SCHEMA.Tables t ON c.TABLE_NAME = t.TABLE_NAME AND t.TABLE_TYPE = 'BASE TABLE'
    WHERE DATA_TYPE = 'uniqueidentifier'
    )

SELECT @table = TABLE_NAME, @column = COLUMN_NAME FROM ColumnID WHERE ID = @begin

SET @sql = 'INSERT INTO #_results SELECT DISTINCT ''' + @table + ''' AS TableName, ''' + @column + ''' AS ColumnName FROM [' + @table + '] WHERE [' + @column + '] = ''' + @uniqueID + '''' ;

EXECUTE sp_executesql @sql;

SET @begin = @begin + 1

END

SELECT * FROM #_results

DROP TABLE #_Results

4 个答案:

答案 0 :(得分:2)

我不知道这会导致内存不足错误,但您的SQL是:

SET @sql = 'SELECT ''' + @table + ''' AS ''Table Name'', ' + @column + ' AS ''Column Name'' FROM ' + @table + ' WHERE ' + @column + ' = ''' + @uniqueID + '''' 

尝试将其更改为:

SET @sql = 'SELECT DISTINCT ''' + @table + ''' AS TableName, ''' + @column + ''' AS ColumnName FROM [' + @table + '] WHERE [' + @column + '] = ''' + @uniqueID + '''' ;

这会做出以下更改:

  • 从别名中删除空格。这些只会让SQL更加混乱。
  • 在列名称周围添加单引号。
  • 在表格和列名称周围添加方括号,以防它们具有不符合要求的字符。

如果这不起作用,请替换:

EXECUTE sp_executesql @sql;

使用:

SELECT @sql;

查看代码的哪一部分导致问题。

答案 1 :(得分:2)

这听起来像SSMS正在倒下,而不是服务器端。基本上,您向屏幕输出的结果太多,而Management Studio的可用资源不足以显示它们。

您最好的选择是将值写入临时表并使用单个最终SELECT语句。

这是我常用搜索脚本的修改副本供您试用。我在比较大的列集上的LIKE字符串比较上使用这个脚本而不是没有问题的攻击。<​​/ p>

重要提示!

像这样的任何东西;这是一种资源匮乏。最好在测试/开发环境中运行它,不反对实时*

SET NOCOUNT ON;

DECLARE @value uniqueidentifier  = '<put your guid here>'
      , @sql   varchar(4000)
;

IF Object_ID('tempdb..##results', 'U') IS NOT NULL
  BEGIN
    DROP TABLE ##results;
  END
;

-- Temporary table to store SQL statements
CREATE TABLE ##results (
   table_name  sysname
 , column_name sysname
 , hit_count   bigint
);

DECLARE e CURSOR FOR
  SELECT 'INSERT INTO ##results (table_name, column_name, hit_count)'
       + Char(13) + 'SELECT ''' + table_schema + '.' + table_name + ''''
       + Char(13) + '     , ''' + column_name + ''''
       + Char(13) + '     , Count(*)'
       + Char(13) + 'FROM   ' + QuoteName(table_schema) + '.' + Quotename(table_name)
       + Char(13) + 'WHERE  ' + QuoteName(column_name) + ' = ' + QuoteName(@value, '''')
       + Char(13) + 'HAVING Count(*) > 0'
       + Char(13) + ';'
  FROM   information_schema.columns
  WHERE  data_type = 'uniqueidentifier'
;

-- Run SQL statements
OPEN e;
FETCH NEXT FROM e INTO @sql;

WHILE @@Fetch_Status = 0
  BEGIN
    EXEC (@sql);
    FETCH NEXT FROM e INTO @sql;
  END
;
CLOSE e;
DEALLOCATE e;

SET NOCOUNT OFF;

-- Display results
SELECT table_name
     , column_name
     , hit_count
FROM   ##results
ORDER
    BY table_name
     , column_name
;

我想你会发现这对你更有效。

答案 2 :(得分:1)

这是我将使用的脚本:

DECLARE @sql NVARCHAR(MAX),
        @TableName SYSNAME,
        @ColumnName SYSNAME,
        @uniqueID nvarchar(100) = 'XXX';

IF OBJECT_ID(N'tempdb..#Results', 'U') IS NOT NULL
    DROP TABLE #Results;

CREATE TABLE #Results 
(
    TableName SYSNAME,
    columnName SYSNAME
);
DECLARE TableCursor CURSOR STATIC LOCAL FORWARD_ONLY READ_ONLY
FOR
    SELECT  TableName = QUOTENAME(OBJECT_SCHEMA_NAME(c.object_id)) + '.' + QUOTENAME(OBJECT_NAME(c.object_id)),
            ColumnName = QUOTENAME(c.name)
    FROM    sys.columns c
            INNER JOIN sys.tables t
                ON t.object_id = c.object_id
            INNER JOIN sys.types ty
                ON ty.system_type_id = c.system_type_id
                AND ty.user_type_id = c.user_type_id
    WHERE   ty.Name = 'uniqueidentifier';

OPEN TableCursor;

FETCH NEXT FROM TableCursor INTO @TableName, @ColumnName;

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @SQL = 'SELECT TOP 1 @Table, @Column FROM ' + @TableName + ' WHERE ' + @Columnname + ' = @UniqueID';
    PRINT @SQL;
    INSERT #Results (TableName, ColumnName)
    EXECUTE sp_executesql @SQL, N'@Table SYSNAME, @Column SYSNAME, @uniqueID UNIQUEIDENTIFIER', @TableName, @ColumnName, @uniqueID;

    FETCH NEXT FROM TableCursor INTO @TableName, @ColumnName;
END

CLOSE TableCursor;
DEALLOCATE TableCursor;

SELECT  *
FROM    #Results;

我已经用游标替换了while循环,因为它会表现得更好,并且我已经用对SQL Server特定系统视图的引用替换了对信息模式的引用,因为它们更可靠。

答案 3 :(得分:1)

对于第二个问题,要计算查询产生的行数,可以使用@@ rowcount,其中包含上次操作选择,删除,更新或插入的行数。

if(@@ rowcount&gt; 0)

select 'Good'

否则

select 'Nothing'