【问题标题】:Get number of rows for tables across all databases获取所有数据库中表的行数
【发布时间】:2015-01-29 20:23:15
【问题描述】:

搜索了一下,没有看到任何真正符合我需求的东西(尽管除了基本的 select 语句之外,我并不真正了解 SQL,所以也许我只是错过了它)。很多个月前在学校上过 SQL 课。

我有:

  • 运行 SQL 2008 R2 的虚拟 Windows Server 2008 R2。我通过 MS SQL Server Management Studio 连接
  • 90-100 个数据库
  • 所有数据库都有相同的表结构(每个都是不同的客户端)

我想:

  • 搜索所有数据库并返回所有具有大于 5000 条记录的表 (TableName) 的数据库的列表。
  • 我可以安排使用该列表的某种脚本,如果它发现 TableName 表超过 5000 条记录的数据库,则会删除超过 x 天(例如 30 天)的任何内容。任何类型的日志记录都可以了解过去几天发生的事情。

任何帮助将不胜感激。谢谢。

编辑/更新(2/24/15):Hiren Dhaduk 提供了一个很好的存储过程。谢谢!

【问题讨论】:

    标签: sql sql-server sql-server-2008


    【解决方案1】:

    您可以在任何数据库中使用以下存储过程。然后通过传递表名和 NoOfRows(表的最小行数,在您的情况下为 5000)运行此存储过程:

    CREATE PROCEDURE usp_FindLargeTables
    @TableName VARCHAR(256) , @NoOfRows int
    AS
    BEGIN
        DECLARE @DBName VARCHAR(256)
        DECLARE @varSQL VARCHAR(512)
        DECLARE @getDBName CURSOR
    
    SET @getDBName = CURSOR FOR
    SELECT name
    FROM sys.databases
    WHERE state != 6
    
    CREATE TABLE #TmpTable (TableName VARCHAR(256),
    SchemaName VARCHAR(256),
    DBName VARCHAR(256))
    
    OPEN @getDBName
    FETCH NEXT
    FROM @getDBName INTO @DBName
    WHILE @@FETCH_STATUS = 0
    BEGIN
    
        SET @varSQL =  'USE ' + @DBName + ';
        INSERT INTO #TmpTable
        SELECT 
        sysobjects.Name as TableName
        , sysindexes.Rows as NoOfRows , '''+ @DBName + ''' AS DBName
        FROM
        sysobjects
        INNER JOIN sysindexes
        ON sysobjects.id = sysindexes.id
        WHERE
        type = ''U''
        AND sysindexes.IndId < 2 
        and sysobjects.Name = '''+ @TableName +''' and sysindexes.Rows > ' + CONVERT(VARCHAR, @NoOfRows) + ''
    
    EXEC (@varSQL)
    FETCH NEXT
    FROM @getDBName INTO @DBName
    END
    CLOSE @getDBName
    DEALLOCATE @getDBName
    
    SELECT *
    FROM #TmpTable
    WHERE DBName != 'master'
    
    -- STEP 2
    DECLARE @DYNAMICQUERY VARCHAR(MAX)
    
    SET @DYNAMICQUERY = 
    REPLACE((
    SELECT 'DELETE FROM ['+ DBName +'].[dbo].['+ TableName +'] where Createdate   < DATEADD(day, -30, GETDATE());'
    FROM #TmpTable
    WHERE DBName != 'master'
    FOR XML PATH('')
    ), '&lt;' , '<');
    
    EXEC(@DYNAMICQUERY);
    
    DROP TABLE #TmpTable
    END
    

    示例:usp_FindLargeTables 'DeltaStuds',5000

    澄清你的第二点:

    除非您在更改发生时运行跟踪,否则这是不可能的。

    为此,我建议您在此表中放置一个名为 createdate 的列,然后您将能够删除 30 天之前创建的记录。

    【讨论】:

    • 感谢@Hiren Dhaduk,我也会对此进行测试并报告。
    • 好的,如果您发现有关在不维护列的情况下获取行的插入日期的信息,请分享
    • 嗨@Hiren Dhaduk,您提供的第一个查询仅适用于一个数据库......而不是所有数据库。它有效,但仅适用于我运行查询的数据库。
    • 另外,@Hiren Dhaduk,我尝试使用 sp_MSforeachdb 'your query' 包装您的第一个查询,但它返回空白结果。
    • 您的表格可能没有超过 5000 行。
    【解决方案2】:

    您的要求对您的设置非常定制...

    您可以使用以下查询来识别带有row count greater than 5000 的表

    SELECT sc.name +'.'+ ta.name TableName
     FROM sys.tables ta
     INNER JOIN sys.partitions pa
     ON pa.OBJECT_ID = ta.OBJECT_ID
     INNER JOIN sys.schemas sc
     ON ta.schema_id = sc.schema_id
     WHERE ta.is_ms_shipped = 0 AND pa.index_id IN (1,0)
     and ta.name = 'DeltaStuds'
     GROUP BY sc.name,ta.name
     having SUM(pa.rows)>5000
    

    但您需要类似此链接的内容才能为所有数据库运行它。 How to find column names for all tables in all databases in SQL Server。我不知道更简单的方法...

    对于第二部分,您必须设置一个删除过程,该过程从上述查询中获取结果集,创建一个动态查询并根据您的日期字段删除行。在该过程中,您可以注入一个审计机制,记录删除操作、行数、日期时间等...

    【讨论】:

    • 感谢@SoulTrain。我会对此进行测试并报告。
    • 嘿@SoulTrain,我尝试用 sp_MSforeachdb 'your query' 包装您的查询,但它返回空白结果。它运行了,没有出错,只是返回了一堆列标题。
    • 我知道至少有两个数据库有一个包含 150,000 多条记录的 DeltaStuds 表(这就是我试图弄清楚这一点的原因,所以我可以运行一个预定的进程来删除大部分(如果不是全部)记录,因为一旦它变得那么大就会导致错误)。 @SoulTrain
    猜你喜欢
    • 2021-10-17
    • 1970-01-01
    • 2019-02-22
    • 2011-12-15
    • 2016-05-13
    • 1970-01-01
    • 2016-06-28
    • 2016-09-14
    • 2010-09-22
    相关资源
    最近更新 更多