从SQL Server的所有数据库中获取表大小信息

时间:2015-12-29 09:22:15

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

我有这个脚本,它会为我提供特定数据库的表大小。

我的问题是如何重写代码,以便它可以从SQL Server返回所有表大小信息,无论数据库是什么,这意味着我不需要更改use_db

[use_db]
SELECT t.name AS TableName,
       p.rows AS RowCounts,
       SUM(a.total_pages) * 8 AS TotalSpaceKB,
       SUM(a.used_pages) * 8 AS UsedSpaceKB,
       (SUM(a.total_pages) - SUM(a.used_pages)) * 8 AS UnusedSpaceKB
FROM sys.tables t
INNER JOIN sys.indexes i ON t.object_id = i.object_id
INNER JOIN sys.partitions p ON i.object_id = p.object_id AND i.index_id = p.index_id
INNER JOIN sys.allocation_units a ON p.partition_id = a.container_id
WHERE t.name NOT LIKE 'dt%'
    AND t.is_ms_shipped = 0
    AND i.object_id > 255
GROUP BY t.name,
         p.rows
ORDER BY t.name

2 个答案:

答案 0 :(得分:4)

IF OBJECT_ID('tempdb.dbo.#space') IS NOT NULL
    DROP TABLE #space

CREATE TABLE #space (
      [db_name] SYSNAME
    , obj_name SYSNAME
    , total_pages BIGINT
    , used_pages BIGINT
    , total_rows BIGINT
)

DECLARE @SQL NVARCHAR(MAX)

SELECT @SQL = STUFF((
    SELECT '
    USE [' + d.name + ']
    INSERT INTO #space ([db_name], obj_name, total_pages, used_pages, total_rows)
    SELECT DB_NAME(), SCHEMA_NAME(o.[schema_id]) + ''.'' + o.name, t.total_pages, t.used_pages, t.total_rows
    FROM (
        SELECT
              i.[object_id]
            , total_pages = SUM(a.total_pages)
            , used_pages = SUM(a.used_pages)
            , total_rows = SUM(CASE WHEN i.index_id IN (0, 1) AND a.[type] = 1 THEN p.[rows] END)
        FROM sys.indexes i
        JOIN sys.partitions p ON i.[object_id] = p.[object_id] AND i.index_id = p.index_id
        JOIN sys.allocation_units a ON p.[partition_id] = a.container_id
        WHERE i.is_disabled = 0
            AND i.is_hypothetical = 0
        GROUP BY i.[object_id]
    ) t
    JOIN sys.objects o ON t.[object_id] = o.[object_id]
    WHERE o.name NOT LIKE ''dt%''
        AND o.is_ms_shipped = 0
        AND o.type = ''U''
        AND o.[object_id] > 255;'
    FROM sys.databases d
    WHERE d.[state] = 0
    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')

EXEC sys.sp_executesql @SQL

SELECT 
      [db_name]
    , obj_name
    , total_rows
    , total_space = CAST(total_pages * 8. / 1024 AS DECIMAL(18,2))
    , used_space = CAST(used_pages * 8. / 1024 AS DECIMAL(18,2))
    , unused_space = CAST((total_pages - used_pages) * 8. / 1024 AS DECIMAL(18,2))
FROM #space

输出 -

db_name                    obj_name                           total_rows  total_space   used_space   unused_space
-------------------------- ---------------------------------- ----------- ------------- ------------ --------------
master                     dbo.Person                         1000        0.20          0.13         0.08
master                     dbo.Building                       4           0.03          0.03         0.00
ReportServer$SQL_2012      dbo.Keys                           1           0.02          0.02         0.00
ReportServer$SQL_2012      dbo.History                        0           0.00          0.00         0.00
ReportServer$SQL_2012      dbo.ConfigurationInfo              20          0.03          0.03         0.00
ReportServer$SQL_2012      dbo.Catalog                        1           0.08          0.08         0.00
ReportServer$SQL_2012      dbo.UpgradeInfo                    1           0.02          0.02         0.00

答案 1 :(得分:2)

有几种方法可以做到这一点。您可以使用未记录的SQL Server过程msForEachDb。它针对当前实例上的每个db执行传递的SQL语句。问号将替换为当前的数据库名称。

对于每个Db示例

/* Undocumented sp can loop over every db on the server.
 */
EXECUTE msdb..sp_msForEachDb
    '
        USE [?];

        SELECT DB_NAME();
    '
;

这种方法的问题在于它没有记录。这意味着MS可以随时撤回或更改SP。

另一种可能更安全的方法是查询系统目录。您可以使用它们来构建可以执行的动态SQL语句。

系统目录示例

/* Using system tables to obtain and query each db,
 * via dynamic SQL statement.
 */
DECLARE @query NVARCHAR(MAX)  = '';

SELECT
    @query = @query + 'USE [' + Name + ']; SELECT DB_NAME();'
FROM
    sys.databases
;

EXECUTE sp_ExecuteSql @query;
;

您也可以在SSIS中使用WHILE循环或CURSOR获得相同的结果。