SQL Server evaluation period has expired

El día de hoy uno de mis clientes me reporto que sus servicios de SQL Server estaban caídos, cuando entre a revisarlos vi que efectivamente éstos estaban caídos, sin embargo cuando revise el log de errores de SQL Server para buscar alguna pista por la cual estaban caídos me encontré con los siguiente: Sigue leyendo “SQL Server evaluation period has expired”

Migración y Upgrade con Database Mirroring

 

El objetivo de este post es auto-documentar un proceso de migración y upgrade de una base de datos SQL Server 2014 a un nuevo servidor con SQL Server 2017 que tuve a cargo. Durante este proceso tuve que solucionar una serie de problemas los cuales también hago referencia en este post por si a alguien también le sucede. El requerimiento principal era minimizar el tiempo de desconexión de las aplicaciones con la base de datos. Documentación y blogs sobre este tema hay muchos, pero la gran mayoría en ingles por eso me anime también a documentarlo en español. Sigue leyendo “Migración y Upgrade con Database Mirroring”

Asegurando los Servicios de SQL Server – Parte 1

SQL Server tiene una serie de servicios los cuales cumplen labores especificas y muy importantes para el correcto funcionamiento del motor de base de datos. Como buenos DBAs debemos asegurara que los servicios de nuestras instancias de base de datos estén correctamente asegurados en relación a las cuentas de usuarios que se utilizan para que estos se ejecuten, ya que los permisos que estas tengan pueden causar problemas mayúsculos en el sistema operativo donde estos corren o incluso en la red donde nuestra instancia esta alojada. Sigue leyendo “Asegurando los Servicios de SQL Server – Parte 1”

Copiar Linked Servers

Hola amigos, el dia de hoy tuve un requerimiento en el que necesitaba copiar una serie de Linked Servers de una instancia de base de datos hacia otra, dichos linked servers apuntaban a una instancia Oracle. Los que tenemos algo de experiencia tratando con bases de datos Oracle, sabemos que estas requieren algunas preparaciones previas para configurar los linked servers desde SQL Server. A continuación vamos a ver los pasos seguidos para poder realizar esta tarea sin tener mayores contratiempos. Sigue leyendo “Copiar Linked Servers”

Estructura Interna del Log de Transacciones

Como habíamos revisado hace algún tiempo en este post, las bases de datos en SQL Server cuentan con dos tipos de archivos, los cuales son: los datafiles y el transaction log. Ya habíamos también revisado de manera general, en este post, para que servía el transaction log y cual era su importancia dentro de la base de datos. Ahora en este post vamos a dar algunos detalles adicionales sobre su estructura interna.

El log de transacciones de una base de datos esta dividido internamente en secciones llamadas VLF (Virtual Log Files) . Los VLFs se crean automáticamente cuando el log de transacciones se crea o cambia de tamaño, y dependiendo del espacio que se le este asignando a la creación o incremento de tamaño, se crearan más o menos VLFs. A continuación se detallan las reglas  de creación de los VLFs:

  • Porciones de crecimiento menor o igual a 64MB = 4 VLFs
  • Porciones de crecimiento mayor a 64MB y menor o igual a 1GB = 8 VLFs
  • Porciones de crecimiento mayor a 1GB = 16 VLFs

Estas reglas de creación de VLFs están vigentes desde hace mucho tiempo, sin embargo a partir de SQL Server 2014, se agrego una variación a ellas con el propósito de reducir la cantidad de VLFs que se crean en las bases de datos. Esta variación tiene como lógica lo siguiente:

¿La porción de crecimiento es menor a 1/8 del tamaño total del archivo log de transacciones?

  • Si: Se crea solo 1 VLF del tamaño de la porción de crecimiento
  • No: Se crean VLFs siguiendo las reglas de arriba.

Para poder verificar el numero de VLFs creados dentro de una base de datos se debe utilizar el comando: DBCC LOGINFO. Si se ejecuta ese comando desde el contexto de la base de datos que se desea consultar no se necesita enviar ningún parámetro, pero si se desea consultar los VLFs de una base de datos distinta a la que estamos conectados debemos de pasar el nombre de la base de datos como parámetro:

DBCC LOGINFO('master')

Ssms_2018-01-29_12-24-37

En el resultado producido por el comando anterior, la columna “Status” es la que nos indicara si ese VLF esta “Activo”, es decir, contiene registros de transacciones que no pueden ser sobre escritas, ya sea porque pertenecen a una transacción activa o aun no se ha respaldado el log de transacciones con un backup de log. Esta ultima razón es valida cuando la base de datos se encuentra en modelo de recuperación Full o Bulk-logged. Es importante mantener un adecuado control de VLFs “Activos” (Status=2), ya que esto determina si el autocrecimiento del log de transacciones se disparará cuando no hayan más VLFs Inactivos (Status=0) dentro de nuestra base de datos.

Ahora, la pregunta que algunos pueden estarse haciendo es, ¿y eso … que tiene de malo? Bueno, para comenzar, esa es la razón por la que muchas bases de datos tienen archivos de log de transacciones bastante grandes, en ocasiones, incluso mas grandes que la misma data de la base de datos. Y la otra razón muy importante es que si se disparan muchos eventos de auto crecimiento se crearan también muchos VLFs, y eso causara un archivo de log altamente fragmentado que experimentara problemas de performance cuando se generen los backups de log y cuando se da el proceso de recuperación de la base de datos.

A continuación vamos a ver un ejemplo de creación de una base de datos con un log de transacciones de 512 MB. Según las reglas definidas, este debería nacer con 8 VLFs:

USE [master]
GO
IF DB_ID('VLFDB') > 0
  DROP DATABASE [VLFDB]
go
CREATE DATABASE [VLFDB]
  ON  PRIMARY
    (
      NAME = VLFDB,
      FILENAME = N'F:\SQL2K16\DATA\VLFDB.mdf' ,
      SIZE = 512 MB ,
      MAXSIZE = UNLIMITED,
      FILEGROWTH = 1024KB
    )
  LOG ON
    (
      NAME = VLFDB_log,
      FILENAME = N'G:\SQL2K16\LOG\VLFDB_log.ldf' ,
      SIZE = 512 MB ,
      MAXSIZE = UNLIMITED ,
      FILEGROWTH = 64 MB
    )
GO
use [VLFDB]
GO
DBCC LOGINFO

Ssms_2018-01-30_12-14-08

Ahora veremos que sucede si agrego más espacio a mi log de transacciones, específicamente lo agrandaremos a 576 MB, es decir 512 MB (tamaño original) + 64 MB (porción de crecimiento), por lo tanto la porción de crecimiento es 64MB, lo cual es exactamente 1/8 del tamaño original de mi log de transacciones. Según las reglas explicadas en este post se deberían crear 4 VLFs ya que la porción de espacio que se agrego no es menor a 1/8 sino igual a 1/8. Veamos:

ALTER DATABASE [VLFDB]
  MODIFY FILE
    (name = VLFDB_log
    ,size = 576 MB)
GO
use [VLFDB]
GO
DBCC LOGINFO

2018-01-30_12-29-41

Ahora agregaremos 64MB adicionales al log de transacciones, esto hará que mi archivo tenga un tamaño total de 640 MB. Los 64MB adicionales, ahora si son menor al 1/8 del tamaño total del log (576 MB), por ende se debería crear un solo VLF:

ALTER DATABASE [VLFDB]
  MODIFY FILE
    (name = VLFDB_log
    ,size = 640 MB)
GO
use [VLFDB]
GO
DBCC LOGINFO

2018-01-30_13-05-48

Como podemos observar nuestro log de transacciones se comporta como lo esperábamos con respecto a las reglas expuestas en este post. Espero haber sido claro con respecto a los VLFs, en caso tengan alguna duda por favor hacérmela saber en los comentarios.

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”

Historial de Backups y Restores para una Base de Datos

Hola, en esta ocación quisiera contribuir con un script que he desarrollado ya hace algun tiempo y me ha sido muy util al momento de adminstrar bases de datos, y es que hay veces en las que se requiere saber cuando fue el ultimo backup full o de log de una base de datos, o cuando fue la ultima vez que fue restaurada y que archivo se tomo para poder hacer la restauración. Este tipo de preguntas pueden ser un poco complicadas de responder cuando no se ha manejado la base de datos desde el comienzo (nacimiento) lo cual en muchos casos no pasa asi.

Con respecto a los backups, entre los datos mas relevantes del script se indica cuando fue ejecutado el backup, la duración de la operación de backup, el tamaño del archivo de backup generado, y el tipo de backup (Database, Diferencial y Log) y la ubicación del mismo. Con estos datos sera muy facil identificar la cadena de backups para una base de datos

Con respecto a las operaciones de restore, el scritp entre sus datos mas relevantes tiene: la fecha de la operación de  restore, el tamaño del backup restaurado, el tipo de backup que fue restaurado (Database, Diferencial y Log) y el servidor y la ubicación de donde proviene el backup. Es importante mencionar que para las operaciones de restore se muestra “Unknown” en la columna “Duration” debido a que no se tiene el dato de cuanto tiempo tardo realizar la operacion de restore.

Ahora para poder identificar el tipo de operacion mostrada en el historial es importante ver el valor de la columna “Operation_Type”, los posibles valores son “BACKUP” y “RESTORE”. Adicionalmente es importante mencionar que el script esta hecho para mostrar el historial de backups y restores de una sola base de datos al mismo tiempo, ademas no es necesario modificar el script para colocar el nombre de la base de datos de la cual se desea ver el historial, simplemente se debe de ejecutar sobre la base de datos que desea consultar, el script sacara el historial de la base de datos de la conexion que se uso para ejecutarlo.

Ahora sin mas preambulos el script:


select
bs.database_name as TargetDatabase
,bs.backup_start_date as Operation_Date
,cast(datediff(minute,bs.backup_start_date,bs.backup_finish_date)/60 as varchar) + ' hours ' +
cast(datediff(minute,bs.backup_start_date,bs.backup_finish_date)%60 as varchar) + ' minutes ' +
cast(datediff(second,bs.backup_start_date,bs.backup_finish_date)%60 as varchar) + ' seconds'
as [Duration]
,cast(bs.backup_size/1024/1024 as decimal(22,2)) as [BackupSize(MB)]
,'BACKUP' as Operation_Type
,case bs.type
when 'D' then 'Database'
when 'L' then 'Log'
when 'I' then 'Differential'
end as BackupType
,bs.user_name as [User]
,bmf.physical_device_name as BackupFile
,bs.server_name as ServerOrigin
,bs.recovery_model
,bs.begins_log_chain
,bs.is_copy_only
,bms.software_name as BackupSoftware
from msdb.dbo.backupset bs
inner join msdb.dbo.backupmediaset bms
on bs.media_set_id = bms.media_set_id
inner join msdb.dbo.backupmediafamily bmf
on bms.media_set_id = bmf.media_set_id
where bs.database_name = db_name()
and bs.server_name = serverproperty('servername')

union all

select
rh.destination_database_name
,rh.restore_date as operation_date
,'Unknown' as [Duration]
,cast(bs.backup_size/1024/1024 as decimal(22,2)) as [BackupSize(MB)]
,'RESTORE' as Operation_Type
,case rh.restore_type
when 'D' then 'Database'
when 'L' then 'Log'
when 'I' then 'Differential'
end as BackupType
,rh.user_name as [User]
,bmf.physical_device_name as BackupFile
,bs.server_name as ServerOrigin
,bs.recovery_model
,bs.begins_log_chain
,bs.is_copy_only
,bms.software_name as BackupSoftware
from msdb.dbo.backupset bs
inner join msdb.dbo.backupmediaset bms
on bs.media_set_id = bms.media_set_id
inner join msdb.dbo.backupmediafamily bmf
on bms.media_set_id = bmf.media_set_id
inner join msdb.dbo.restorehistory rh
on bs.backup_set_id = rh.backup_set_id
where rh.destination_database_name = db_name()
order by 2 desc

Espero les sea util. Hasta una proxima oportunidad.