Fala pessoal!
Nesse post de hoje, gostaria de compartilhar uma solução que criei para responder uma dúvida em um dos grupos do Telegram em que participo, que foi a pergunta de como saber há quanto tempo um database está online no SQL Server. Isso não é há quanto tempo a instância está online e sim há quanto tempo um database está online.

Para resolver essa dúvida, pensei em utilizar o próprio log do SQL Server para identificar quando cada database foi iniciado e retornar para o usuário. A query abaixo irá retornar todos os bancos que estão no último arquivo de log, junto com a data da última vez que o banco foi inicializado e o tempo decorrido desde então até a hora atual.

IF (OBJECT_ID('tempdb..#StartupDB') IS NOT NULL) DROP TABLE #StartupDB
CREATE TABLE #StartupDB (
    [LogNumber] TINYINT,
    [LogDate] DATETIME,
    [ProcessInfo] NVARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AI, 
    [Text] NVARCHAR(MAX) COLLATE SQL_Latin1_General_CP1_CI_AI,
    [Database] AS (REPLACE(REPLACE(SUBSTRING([Text], CHARINDEX('''', [Text]), 128), '''', ''), '.', ''))
)

INSERT INTO #StartupDB (LogDate, ProcessInfo, [Text]) 
EXEC master.dbo.sp_readerrorlog 0, 1, N'Starting up database ', NULL

SELECT
    [Database],
    MAX(LogDate) AS LogDate,
    (CASE WHEN DATEDIFF(SECOND, MAX(LogDate), GETDATE()) > 86400 THEN CAST(DATEDIFF(SECOND, MAX(LogDate), GETDATE()) / 86400 AS VARCHAR) + 'd ' ELSE '' END) + 
    RIGHT('00' + CAST((DATEDIFF(SECOND, MAX(LogDate), GETDATE()) / 3600) % 24 AS VARCHAR), 2) + ':' + 
    RIGHT('00' + CAST((DATEDIFF(SECOND, MAX(LogDate), GETDATE()) / 60) % 60 AS VARCHAR), 2) + ':' + 
    RIGHT('00' + CAST(DATEDIFF(SECOND, MAX(LogDate), GETDATE()) % 60 AS VARCHAR), 2) + '.' + 
    RIGHT('000' + CAST(DATEDIFF(SECOND, MAX(LogDate), GETDATE()) AS VARCHAR), 3) 
    AS TimeRunning
FROM
    #StartupDB
GROUP BY
    [Database]
ORDER BY 1

Resultado:

Caso você queira analisar todo o histórico de inicialização dos databases, varrendo por todos os arquivos de logs (não somente o último):

IF (OBJECT_ID('tempdb..#Arquivos_Log') IS NOT NULL) DROP TABLE #Arquivos_Log
CREATE TABLE #Arquivos_Log ( 
    [idLog] INT, 
    [dtLog] NVARCHAR(30) COLLATE SQL_Latin1_General_CP1_CI_AI, 
    [tamanhoLog] INT 
)

IF (OBJECT_ID('tempdb..#StartupDB') IS NOT NULL) DROP TABLE #StartupDB
CREATE TABLE #StartupDB (
    [LogNumber] TINYINT,
    [LogDate] DATETIME, 
    [ProcessInfo] NVARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AI, 
    [Text] NVARCHAR(MAX) COLLATE SQL_Latin1_General_CP1_CI_AI,
    [Database] AS (REPLACE(REPLACE(SUBSTRING([Text], CHARINDEX('''', [Text]), 128), '''', ''), '.', ''))
)


INSERT INTO #Arquivos_Log
EXEC sys.sp_enumerrorlogs

DECLARE
    @Contador INT = 0,
    @Total INT = (SELECT COUNT(*) FROM #Arquivos_Log)
    
 
WHILE(@Contador < @Total)
BEGIN
    
    INSERT INTO #StartupDB (LogDate, ProcessInfo, [Text]) 
    EXEC master.dbo.xp_readerrorlog @Contador, 1, N'Starting up database ', NULL, NULL, NULL
 
    -- Atualiza o número do arquivo de log
    UPDATE #StartupDB
    SET LogNumber = @Contador
    WHERE LogNumber IS NULL
 
    SET @Contador += 1
    
END
 

SELECT * 
FROM #StartupDB
ORDER BY LogDate DESC

Resultado:

Nas duas soluções apresentadas, você pode usar a coluna de “Database” para filtrar os bancos selecionados e acredito que a dúvida original foi respondida por esses 2 scripts.

É isso aí, pessoal! Espero que tenham gostado dessa dica. Você conhece alguma outra solução para responder essa dúvida? Deixe aqui nos comentários 🙂

Um grande abraço e até a próxima!