Saltar al contenido

Diario de un DBA

Problemas y soluciones para SQL Server

Menú
  • Inicio
  • Consultoria gratuita
  • tempdb
  • Curso Azure DP-300
  • Rendimiento
  • Seguridad
  • Sobre Mi
Menú

Cómo saber el espacio que puedo liberar haciendo un shrink en SQL Server

Publicada el agosto 20, 2022junio 29, 2024 por solracamo

Contenido del post:

Toggle
  • ¿Qué es un shrink en SQL Server?
  • Hacer un shrink a los archivos de datos
  • Hacer un shrink a los logs de las base de datos
  • Hacer un shrink a los archivos de la tempdb
  • ¿Todavía tienes dudas?

Cuando damos soporte a servidores SQL uno de los problemas más habituales es es el espacio libre en los discos duros, o mejor dicho, la falta de espacio en estos discos. Esto nos obliga a los DBA a tener que liberar espacio con shrink habitualmente.

Por lo general, las empresas no son muy dadas a tener mucho espacio sin utilizar en los discos ya que esto puede significar un coste monetario elevado por algo que no están usando (o eso creen), por lo que lo normal es encontrar que los discos que están siendo usados por la instancia SQL Server tienen un espacio libre de entre el 10 y el 30%.

Para que tengáis una referencia, en mi actual empresa recibimos alertas «warning» cuando el disco baja del 20% de espacio libre y alertas «criticas» cuando baja del 10%, y aún así algunos clientes prefieren bajarlo al 10% y 5% respectivamente.

Cuando recibimos una de estas alertas, lo primero que hacemos es informar al cliente ya que ellos pueden decidir si quieren ampliar el espacio en el disco (rara vez ocurre si pueden evitarlo) o si prefieren que intentemos hacer algún shrink a los archivos de las bases de datos.

¿Qué es un shrink en SQL Server?

Podría ponerme muy técnico, pero un shrink básicamente consiste en intentar recuperar todo ese espacio que los archivos de la base de datos están consumiendo pero no están usando y se puede aplicar a los archivos de datos, a los logs y a los archivos de datos de la TempDB.

El problema surge cuando el servidor tiene muchas bases de datos y revisar una por una la base de datos para comprobar el espacio libre disponible se vuelve una tarea muy pesada, por lo que aquí os dejo 3 scripts que os harán este trabajo increíblemente más sencillo.

Hacer un shrink a los archivos de datos

El siguiente script nos mostrará el nombre del archivo de datos, a que base de datos pertenece, en que disco está almacenado, el espacio que está ocupando , el espacio que está usando realmente y cuanto espacio podemos ganar si hacemos un shrink sobre él. Además, también nos genera 2 scripts, uno para truncar el archivo y para hacer shrink.

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

CREATE TABLE #DBsizes
(
    ServerName nvarchar(max),
    DBname nvarchar(max),
    Filename nvarchar(max),
    CurrentSize INT,
    SpaceUsed	INT,
    CurrentAvailableSpace	INT,
    Growth INT,
    Physical nvarchar(max),
    status INT,
)

EXEC sp_MSforeachdb'
USE [?]
INSERT INTO #DBsizes
SELECT
        @@SERVERNAME,
        db_name(),
        ms.name, 
        -- Current Size		
        sf.size/128,
        -- Used space
        fileproperty(sf.name,''SpaceUsed'')/128,
        -- Current Available space
        (sf.size-fileproperty(sf.name,''SpaceUsed''))/128,
        CASE
            WHEN sf.growth < 0 THEN -1
            WHEN sf.growth = 0 THEN 0
            ELSE (sf.growth)/128
        END,
        ms.filename,
        sf.status
FROM	master.dbo.sysaltfiles ms, dbo.sysfiles sf
WHERE	dbid = DB_ID()
        AND ms.fileid = sf.FILEID
        AND sf.groupid <> 0
        AND dbid <> 2
';

WITH Cte
AS
(
SELECT
    DBname,
    Filename,
    SUBSTRING(Physical,1,1) as [Drive],
    CurrentSize,
    SpaceUsed,
    Growth,
    CASE
        WHEN Growth <= 0 THEN (SpaceUsed*1)+1
        ELSE ((SpaceUsed/Growth) + 1) * Growth
    END as TargetSize,
    'USE ' + QUOTENAME(DBname) + '; DBCC SHRINKFILE(N'''+Filename+''' , 0, TRUNCATEONLY);' as 'TruncateOnly',
    CASE
        WHEN Growth <= 0 THEN 'USE ' + QUOTENAME(DBname) + '; DBCC SHRINKFILE(N'''+Filename+''' , '+CAST(CAST((SpaceUsed*1) + 1 AS FLOAT) as NVARCHAR(MAX))+' );'
        ELSE 'USE ' + QUOTENAME(DBname) + '; DBCC SHRINKFILE(N'''+Filename+''' , '+ CAST(CAST((((SpaceUsed/Growth) + 1) * Growth) AS FLOAT) as NVARCHAR(MAX)) +');'
    END as 'ShrinkFile'
FROM #DBsizes
)
SELECT 
    DBname,
    Filename,
    Drive,
    CurrentSize,
    SpaceUsed,
    CAST(SpaceUsed as FLOAT)*100.0/(CurrentSize+1) as 'SpaceUsed_Pct',
    TargetSize,
    CurrentSize - TargetSize as [PotentialGain],
    CAST(CurrentSize - TargetSize as FLOAT)*100.0/(CurrentSize+1) as 'PotentialGain_Pct',
    TruncateOnly,
    ShrinkFile
FROM cte
ORDER BY Drive ASC, PotentialGain DESC

IF OBJECT_ID('tempdb..#DBsizes') IS NOT NULL

    DROP TABLE #DBsizes

Esto será el resultado de la ejecución:

 

Hacer un shrink a los logs de las base de datos

Este script hace básicamente lo mismo que el anterior, pero esta vez para los archivos de log de las bases de datos.

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

CREATE TABLE #DBsizes
(
    ServerName nvarchar(max),
    DBname nvarchar(max),
    Filename nvarchar(max),
    CurrentSize INT,
    SpaceUsed	INT,
    CurrentAvailableSpace	INT,
    Growth INT,
    Physical nvarchar(max),
    status INT,
)

EXEC sp_MSforeachdb'
USE [?]
INSERT INTO #DBsizes
SELECT
        @@SERVERNAME,
        db_name(),
        ms.name, 
        -- Current Size		
        sf.size/128,
        -- Used space
        fileproperty(sf.name,''SpaceUsed'')/128,
        -- Current Available space
        (sf.size-fileproperty(sf.name,''SpaceUsed''))/128,
        CASE
            WHEN sf.growth < 0 THEN -1
            WHEN sf.growth = 0 THEN 0
            ELSE (sf.growth)/128
        END,
        ms.filename,
        sf.status
FROM	master.dbo.sysaltfiles ms, dbo.sysfiles sf
WHERE	dbid = DB_ID()
        AND ms.fileid = sf.FILEID
        AND sf.groupid = 0
        AND dbid <> 2
';

WITH Cte
AS
(
SELECT
    DBname,
    Filename,
    SUBSTRING(Physical,1,1) as [Drive],
    CurrentSize,
    SpaceUsed,
    Growth,
    CASE
        WHEN Growth <= 0 THEN (SpaceUsed*1)+1
        ELSE ((SpaceUsed/Growth) + 1) * Growth
    END as TargetSize,
    'USE ' + QUOTENAME(DBname) + '; CHECKPOINT; DBCC SHRINKFILE(N'''+Filename+''' , 0, TRUNCATEONLY);' as 'TruncateOnly',
    CASE
        WHEN Growth <= 0 THEN 'USE ' + QUOTENAME(DBname) + '; CHECKPOINT; DBCC SHRINKFILE(N'''+Filename+''' , '+CAST(CAST((SpaceUsed*1) + 1 AS FLOAT) as NVARCHAR(MAX))+' );'
        ELSE 'USE ' + QUOTENAME(DBname) + '; CHECKPOINT; DBCC SHRINKFILE(N'''+Filename+''' , '+ CAST(CAST((((SpaceUsed/Growth) + 1) * Growth) AS FLOAT) as NVARCHAR(MAX)) +');'
    END as 'ShrinkFile'
FROM #DBsizes
)
SELECT 
    DBname,
    Filename,
    Drive,
    CurrentSize,
    SpaceUsed,
    CAST(SpaceUsed as FLOAT)*100.0/(CurrentSize+1) as 'SpaceUsed_Pct',
    TargetSize,
    CurrentSize - TargetSize as [PotentialGain],
    CAST(CurrentSize - TargetSize as FLOAT)*100.0/(CurrentSize+1) as 'PotentialGain_Pct',
    TruncateOnly,
    ShrinkFile
FROM cte
ORDER BY Drive ASC, PotentialGain DESC

IF OBJECT_ID('tempdb..#DBsizes') IS NOT NULL

    DROP TABLE #DBsizes

shrink sql server

Hacer un shrink a los archivos de la tempdb

Este script es un poco diferente y simplemente truncará todos los archivos de datos de la tempdb de manera automática. Es posible que el shrink no funcione en la tempdb aunque haya espacio disponible, si os pasa esto podéis echar un vistazo a este post donde os explico como solucionarlo.

USE [tempdb]
GO
CHECKPOINT; 
GO
DECLARE @sqlCmd VARCHAR(MAX)
SET @sqlcmd=''
SELECT @sqlCmd = @sqlCmd + 'DBCC SHRINKFILE (' + name + ' ,0, TRUNCATEONLY);'
FROM sys.database_files
--PRINT @sqlCmd
EXEC (@sqlCmd)

Espero que esto os haya resultado útil y hayáis podido eliminar esa alerta de espacio que tan molesta resulta.

¿Todavía tienes dudas?

Si este post no ha solucionado tu problema o todavía tienes dudas sobre este o cualquier otro asunto relacionado con SQL Server, puedes enviarme un mensaje o solicitar una consultoría gratuita haciendo clic aquí.

Deja una respuesta Cancelar la respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Consultoria Gratis

¿Tienes un problema o una consulta sobre tu servidor SQL Server? ¿Necesitas hacer algún tipo de mantenimiento o tarea en tu instancia, pero no tienes claro cómo hacerlo?

Envíame un email con tu caso y te contestaré lo antes posible de forma totalmente gratuita.

Puedes utilizar el formulario que encontrarás haciendo click aquí.

Sobre mi

Efectivamente, soy un muñeco de slack con la camiseta de Fernando Alonso en Renault, pero también soy una DBA mid level que vive y trabaja en inglaterra como consultor SQL Server.

El objetivo de este blog es escribir los problemas con los que me he ido encontrando y cómo los solucioné. Si estas soluciones han servido para mí, es posible que también lo hagan para ti, ¿no?

Otras soluciones

  • Recuperar la password de la cuenta SA en SQL Serveroctubre 5, 2024
  • Always On en SQL Server. Todo lo que necesitas saberagosto 24, 2024
  • Recuperar una tabla borrada en SQL Serveragosto 18, 2024
  • Mover bases de datos a otro disco en SQL Serveragosto 11, 2024
  • Comprobar los últimos backups tomados en una instancia SQL Serverjunio 29, 2024
  • Comprobar fragmentación en SQL Serverjunio 23, 2024

Curso Azure DP-300 Gratis

  • Azure DP-300 curso en Español – Parte 1noviembre 17, 2022
  • Crear una máquina virtual con SQL server en Azurenoviembre 17, 2022
  • Crear un servidor SQL Server en Azure.noviembre 22, 2022
  • Azure DP-300 curso en Español – Parte 2noviembre 24, 2022
  • Azure DP-300 curso en Español – Parte 3diciembre 1, 2022
  • Azure DP-300 curso en Español – Parte 4diciembre 14, 2022

Consulta las páginas que nadie consulta:
Privacidad
Cookies

Escríbeme!
Contacto

© 2025 Diario de un DBA