Mostrar datos y desglose de uso de disco por tabla

9

Tengo una base de datos SQL Server 2008 R2 utilizada por varios programas implementados.

Pregunta: ¿Hay una manera fácil de mostrar cuánto espacio consume cada tabla para todas las tablas de la base de datos y distinguir el espacio lógico del espacio en disco?

Si uso SSMS (Management Studio), las propiedades de almacenamiento que se muestran para la base de datos leen 167 MB con 3 MB "disponibles" (sobre el tamaño correcto, pero me preocupan los 3 MB disponibles. ¿Es este un límite para preocuparse? , suponiendo que sé que tengo suficiente espacio en disco?)

Puedo profundizar en cada mesa, pero eso lleva una eternidad.

Sé que puedo escribir mis propias consultas y probar, pero me gustaría saber si ya hay una manera fácil (¿incorporada?) De hacer esto.

Dronz
fuente

Respuestas:

13

En SSMS, haga clic con el botón derecho en la base de datos y vaya a "Informes", "Informes estándar", "Uso de disco por tabla". Le indicará el tamaño total, el tamaño de los datos, el tamaño del índice y el tamaño no utilizado para cada tabla (así como el recuento de filas).

nateirvin
fuente
1
No lo había visto antes y me gusta más que el script, excepto que en algunas bases de datos falla porque no tengo el permiso "VER ESTADO DE LA BASE DE DATOS", pero el script funcionará en ese caso. ¡Imagínate!
Chris Woodruff
10

Se ha respondido en Stack Overflow:

SELECT 
    t.NAME AS TableName,
    s.Name AS SchemaName,
    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
LEFT OUTER JOIN 
    sys.schemas s ON t.schema_id = s.schema_id
WHERE 
    t.NAME NOT LIKE 'dt%' 
    AND t.is_ms_shipped = 0
    AND i.OBJECT_ID > 255 
GROUP BY 
    t.Name, s.Name, p.Rows
ORDER BY 
    t.Name
Nelz
fuente
5

La consulta vinculada y copiada por @Nelson es inexacta: ignora las vistas indizadas, los índices de texto completo, los índices XML, etc.

Si desea una consulta que incluya todo sin ejecutar a sp_spaceusedtravés de sp_MSForEachTable, entonces ya he publicado dos variaciones (una aquí en DBA.StackExchange y la otra en StackOverflow), así que no las copiaré aquí:

Solomon Rutzky
fuente
4

Solo por diversión, aquí hay una consulta que generará los mismos datos que el informe en la respuesta de nateirvin

create table #disk_usage
(
    name varchar(128)
    ,rows varchar(20)
    ,reserved varchar(20)
    ,data varchar(20)
    ,index_size varchar(20)
    ,unused varchar(20)
);

exec sp_msforeachtable 'insert into #disk_usage exec sp_spaceused [?]'

select SCHEMA_NAME(st.schema_id) + '.' + du.name 'Table Name'
 ,du.rows '# Records'
 ,du.reserved 'Reserved (KB)'
 ,du.data 'Data (KB)'
 ,du.index_size 'Indexes (KB)'
 ,du.unused 'Unused (KB)'
 from #disk_usage du
left join sys.tables st
on du.name = st.name
order by cast(left(reserved, len(reserved) - 3) as bigint) desc;

drop table #disk_usage

De acuerdo, porque realmente me odio a mí mismo, escribí una consulta que generará los resultados del informe, lo formateará como una tabla HTML y lo enviará como un correo electrónico. Hacer coincidir los colores de fondo del informe se deja como ejercicio para el lector.

declare @subject nvarchar(25) = 'Disk Usage by Top Tables';

declare @recipients nvarchar(25) = '[email protected]';

create table #disk_usage
(
    name varchar(128)
    ,rows varchar(20)
    ,reserved varchar(20)
    ,data varchar(20)
    ,index_size varchar(20)
    ,unused varchar(20)
);

exec sp_msforeachtable 'insert into #disk_usage EXEC sp_spaceused [?]'

declare @body nvarchar(max) = 
'<table cellspacing="0">
    <thead>
        <tr>
            <th>Table Name</th>
            <th># Rows</th>
            <th>Reserved</th>
            <th>Data</th>
            <th>Indexes</th>
            <th>Unused</th>
        </tr>
    </thead>
';

set @body = @body + cast (
    (select '<td style="border: 1px solid black; padding: 2px">' + SCHEMA_NAME(s.schema_id) + '.' + t.name + '</td>'
     ,'<td style="border: 1px solid black; padding: 2px">' + rtrim(ltrim(t.rows)) + ' Rows </td>' -- for some reason this was generating a bunch of extra white space and I'm not going to bother to figure out why
     ,'<td style="border: 1px solid black; padding: 2px">' + t.reserved + '</td>'
     ,'<td style="border: 1px solid black; padding: 2px">' + t.data + '</td>'
     ,'<td style="border: 1px solid black; padding: 2px">' + t.index_size + '</td>'
     ,'<td style="border: 1px solid black; padding: 2px">' + t.unused + '</td>'
     from #disk_usage t
    left join sys.tables s
    on t.name = s.name
    order by cast(left(reserved, len(reserved) - 3) as bigint) desc
    for xml path ('tr'))
as nvarchar(max));

set @body = replace(replace(@body, '&lt;', '<'), '&gt;', '>')
set @body = @body + '</table>'

exec msdb.dbo.sp_send_dbmail 
@profile_name='A Database Mail Profile On The Target Server', 
@recipients=@recipients, 
@subject=@subject,
@body=@body,
@body_format='HTML'

drop table #disk_usage
MikeTheLiar
fuente
1
¡Guauu! ¡Ese último pedazo de trabajo impulsado por el autodesprecio es maravilloso (para otros ;-))! Gracias por agregar eso. Lamento tener solo un voto a favor para dar esta respuesta ...
Dronz
1
:) Pensé que si tenía que pasar por el dolor de hacerlo, lo menos que puedo hacer es salvar a otra persona del mismo destino.
MikeTheLiar