Historial de Backups con PowerShell

Hace un tiempo atrás escribí un post acerca del historial de backups y restores de una base de datos, esos scripts estoy seguro que les fueron de mucha utilidad, sin embargo yo sabia tenían algunas limitaciones las cuales requerían que en algunos casos tengamos que hacer cambios al código para que pudiera hacer lo que necesitábamos, pero si no dominábamos las tablas de sistema que están involucradas en el código, estos cambios se tornaban incluso más difíciles. Pues bueno ahora les traigo otra alternativa a esos scripts, este primer post nos guiara en los aspectos mas importantes del cmdlet de Powershell que vamos a utilizar para poder obtener esta misma información y más.

Uno de los pre-requisitos para utilizar este cmdlet es tener instalado el modulo de “dbatools” para lo cual les dejo el enlace aquí. Luego se asume que este comando sera utilizado por un usuario de Windows administrador de la instancia de base de datos de la cual se desea consultar la información. Finalmente es importante notar que no es necesario ejecutar los comandos desde el mismo servidor de base de datos, al contrario, se recomienda que estos se ejecuten desde un terminal cliente.

El comando que utilizaremos se llama “Get-DbaBackupHistory”, el nombre del comando es bastante descriptivo en cuanto a su proposito. Este comando tiene algunos parametros que detallaremos a continuación para modificar su comportamiento o la información que nos arroja:

  • -SqlServer: El servidor SQL Server al cual nos conectaremos.
  • -Credential: Objeto de tipo credencial que utilizaremos si no contamos con un usuario Windows con acceso a la instancia de base de datos.
  • -IgnoreCopyOnly: Si se coloca este parametro, el comando ignorará los backups de tipo “Copy Only”.
  • -Force: Según la documentación arroja toda la información, de la forma en que SQL Server la retorna, sin embargo no he conseguido hacerla funcionar correctamente. Sugiero no se utilice este parámetro.
  • -Since: Define una fecha de inicio desde la cual queremos la información. Esto ayuda a reducir la información retornada.
  • -Last: Retorna la ultima cadena de backups completa, es decir el ultimo backup full, diferencial y logs para traer la base de datos hasta la ultima transacción respaldada.
  • -LastFull: Retorna sólo el ultimo backup Full de las bases de datos.
  • -LastDiff: Retorna sólo el ultimo backup diferencial de las bases de datos.
  • -LastLog: Retorna sólo el ultimo backup de log de las bases de datos.
  • -Raw: Por defecto el comando agrupará los mediasets (backups partidos en multiples archivos) dentro de un solo objeto. si se prefiere tener un objeto por archivo de backup, se debe activar este parámetro.
  • -Databases: La lista de bases de datos, puede ser una o varias.
Ejemplo 1: Obtener el historial de backup de todas las bases de datos de una instancia:
Get-DbaBackupHistory -SqlServer localhost

Ejemplo 2: Obtener el historial de backup de una base de datos:
Get-DbaBackupHistory -SqlServer localhost -Databases master

Ejemplo 3: Obtener la ultima cadena de backups complete (Full, Diferencial, Log):

En este caso sólo mostraría el ultimo full, el ultimo diferencial, y los backups de log que se sacaron luego del ultimo diferencial, estos backups serian los necesarios para restaurar la base de datos hasta la ultima trasacción respaldada.

Get-DbaBackupHistory -SqlServer localhost `
-Databases AdventureWorks2014 -Last

Ejemplo 4: Obtener el ultimo backup full de multiples bases de datos:
Get-DbaBackupHistory -SqlServer localhost `
-Databases AdventureWorks2014,ContosoRetailDW,DBATools `
-LastFull

¿Qué les pareció? muy buena funcionalidad verdad, sin embargo ustedes dirán: “Hey, pero no tengo la ruta ni el archivo de backup”. Los entiendo, yo también me hice esa misma pregunta, sin embargo lo que nos esta exponiendo ese comando de Powershell es un objeto, el cual sólo esta mostrando algunas de sus propiedades, se puede obtener las demás propiedades a través de otros comandos, acá les mostrare sólo algunos ejemplos de lograr esto:

Format-List:
Get-DbaBackupHistory -SqlServer localhost `
-Databases AdventureWorks2014,ContosoRetailDW,DBATools -LastFull | 
Format-List

Select:
Get-DbaBackupHistory -SqlServer localhost `
-Databases AdventureWorks2014 -Last |
select Database,Start,Duration,Path


Como podemos darnos cuenta con Powershell contamos con muchas más posibilidades de obtener la información que necesitamos para obtener el historial de backups de nuestras bases de datos. Los animo a seguir experimentando con Powershell y SQL Server. Nos vemos en el próximo post.

Instalando Modulo DBATools

Hola, tal y como lo comente en mi entrada anterior existe un modulo de powershell creado inicialmente por Chrissy LeMaire (b|t), este modulo fue inicialmente concebido como una serie de comandos para hacer una migración entre instancias SQL Server de forma sencilla a través de Powershell, sin embargo con el paso del tiempo y el entusiasmo de la comunidad por querer hacer de este modulo algo mas que una herramienta para migración entre de instancias, una serie de personajes reconocidos en la comunidad de SQL Server se unieron a Chrissy para añadir más funcionalidad a este modulo y de esta manera pueda ser aprovechada por todos los DBAs que día a día luchamos para poder mantener nuestras bases de datos en linea y corriendo. Sigue leyendo “Instalando Modulo DBATools”

Introducción a Powershell para DBAs

Estimados amigos, hace relativamente poco tiempo he podido descubrir que PowerShell brinda un sinfín de posibilidades para automatizar nuestras tareas rutinarias tanto a nivel de base de datos como a nivel de la administración propia de los servidores; sí imagino lo que algunos estan pensando,  al parecer he vivido bajo de una roca y no he podido darme cuenta antes de todas las ventajas que ofrece PowerShell no sólo para los DBAs sino para los administradores de servidores en general.

Sigue leyendo “Introducción a Powershell para DBAs”

Tempdb: Reducir Tamaño

Bienvenidos nuevamente, este post es sobre un tema que seguramente muchos de ustedes han tenido que enfrentar, y es que hay ocaciones en las cuales  uno se encuentra con que el disco del servidor que aloja nuestra “tempdb” se encuentra casi llego y algunos procesos que demandan gran espacio en ella se caen justamente por falta de espacio. Sigue leyendo “Tempdb: Reducir Tamaño”

¿Qué job actualizo mi tabla?

Estimados,

Les voy a contar una anécdota que me sucedió hace algún tiempo y que me sirvió para poder buscar información y aprender más sobre historial de los jobs de base de datos lo cual me fue de mucha ayuda en esa situación. Pues bueno tenía una base de datos que contenía muchas tablas y estas eran llenadas desde diversos jobs los cuales estaban programados en diversos servidores, no se tenía un mapa completo del origen de los datos de cada una de esas tablas; hasta que un desafortunado día un jefe me dice: “… Hey, ¿puedes verificar por qué la tabla X no se ha llenado?” Sigue leyendo “¿Qué job actualizo mi tabla?”

El Datafile que no podia eliminarse

Empezaré diciendo que el eliminar datafiles de una base de datos no es una tarea que sea del todo recomendada ni mucho menos frecuente dentro de las tareas cotidianas de una DBA, pero hay momentos en los que se va a necesitar realizarla y hay que estar preparados para saber qué hacer si esta falla, como me paso a mí.

Primero hay que entender que los datafiles son los archivos físicos de nuestra base de datos. Cuando creamos una base de datos, se crea por defecto sólo uno (basado en lo que tengamos configurado en nuestra base de datos “model”), el cual tiene como extension *.mdf. Sin embargo, nosotros podemos crear más datafiles, conocidos como secundarios y de extensión *.ndf, los cuales podemos distribuirlos entre los diferentes discos de nuestro servidor.

Ahora en mi caso particular yo estaba buscando refrescar uno de mis ambientes de desarrollo con data más reciente de mi base de datos de producción, pero dado que esta es una base de datos de más de 1TB de información y que se tiene una limitación de espacio en el ambiente de desarrollo, antes de refrescar el ambiente, se hace un trabajo de truncado de tablas de log y otras que no son importantes para el funcionamiento de la aplicación en el ambiente de desarrollo. Luego del proceso de truncado se procede a realizar un shrink de los datafiles (lo cual es algo que JAMAS se debe hacer en producción) y la eliminación de los datafiles que sobran y esto venía funcionando bien desde siempre hasta que un día FALLO.

Esta falla evitaba que el datafile se vaciara completamente, por ende, hacía imposible su eliminación, luego de mucho buscar y ver en los primeros resultados de mi búsqueda que uno nunca va a poder hacer un DBCC SHRINK con EMPTYFILE a un archivo primario (recuerdan el archivo *.mdf, ese es el primario), lo cual ya sabía, solo se puede hacer esto en los secundarios, y el archivo que no podía eliminar era efectivamente un secundario. El mensaje de error que aparecía era el siguiente:

Msg 2555, Level 16, State 2, Line 2
Cannot move all contents of file “xxx” to other places to complete the empty

Entonces lo que se me ocurrio fue buscar que objetos eran los que no se habia podido mover del datafile que queria eliminar, para esto use la siguiente consulta, la cual viene de esta pagina:

CREATE TABLE #Object_Search
(File_id          BIGINT,
Page_id          BIGINT,
pg_alloc         BIGINT,
ext_size         BIGINT,
object_id        BIGINT,
index_id         BIGINT,
partition_number BIGINT,
partition_id     BIGINT,
iam_chain_type   VARCHAR(50),
pfs_bytes        VARCHAR(50)
);
GO

INSERT INTO #Object_Search
EXEC ('DBCC EXTENTINFO(''MyDatabase'')');
GO

DECLARE @id AS INT;
SELECT @id = FILE_ID('xxx');
SELECT DISTINCT
[name]
FROM
(
SELECT OBJECT_NAME(object_id) AS name,
*
FROM #Object_Search
WHERE File_id = @id
) x;

Esto me permitio ubicar la tabla “heap” que no se estaba moviendo, lo que hice para resolver el problema fue crearle un indice cluster, y volver a ejecutar el comando DBCC SHRINKFILE con EMPTYFILE y esta vez si funciono y pude eliminar el archivo que me estaba dado problemas.

Espero que este corto articulo les haya sido de utilidad. Hasta la proxima.

 

Cuanto Durará mi Backup o Restore

Bueno esto es algo que creo que todos se han preguntado en algún momento cuando deciden hacer una operación de backup o restore, especialmente cuando la base de datos de tamaño algo considerable, pues déjenme decirles que si se puede identificar el tiempo que va a tomar una de estas operaciones con un simple script.

Sin embargo hay cosas que deben de considerar cuando ejecuten el script que les dejare líneas más abajo:

  1. Nunca tomen el primer estimado como 100% exacto, hay que dejar que la operación (backup / restore) se asiente, al comienzo comenzara a dar algunos números que cambiaran rápidamente si la base de datos es muy grande. Esperen unos 30 segundos o un minuto luego de iniciada la operación para poder tener un estimado más exacto.
  2. El tráfico de red importa, si están haciendo un backup o restore, desde o hacia una unidad de red, es importante considerar el ratio de transferencia de datos entre estos dos puntos, he visto casos en los que un restore tomaba 20 minutos entre el punto “A” y el punto “B”, sin embargo cuando se hacia el restore desde el punto “A” y el punto “C” demoraba más de 12 horas, y es por el ratio de transferencia.
  3. El estimado es exacto en la mayoría de casos, sin embargo hay veces en las que circunstancias ajenas, tales como sobre carga en alguno de los dos servidores, o cambios en la red pueden hacer que este cambie.

En todos los casos es importante que si el restore tomara mucho tiempo hay que monitorearlo constantemente. A continuación el script, espero les sea de mucha utilidad como a mí.

select
session_id,
convert(nvarchar(22),db_name(database_id)) as [database],
case command
when 'BACKUP DATABASE' then 'DB'
when 'RESTORE DATABASE' then 'DB RESTORE'
when 'RESTORE VERIFYON' then 'VERIFYING'
when 'RESTORE HEADERON' then 'VERIFYING HEADER'
else 'LOG' end as [type],
start_time as [started],
dateadd(mi,estimated_completion_time/60000,getdate()) as [finishing],
datediff(mi, start_time, (dateadd(mi,estimated_completion_time/60000,getdate()))) - wait_time/60000 as [mins left],
datediff(mi, start_time, (dateadd(mi,estimated_completion_time/60000,getdate()))) as [total wait mins (est)],
convert(varchar(5),cast((percent_complete) as decimal (4,1))) as [% complete],
getdate() as [current time]
from sys.dm_exec_requests
where command in ('BACKUP DATABASE','BACKUP LOG','RESTORE DATABASE','RESTORE VERIFYON','RESTORE HEADERON')