Database health checkDiagnóstico do banco — sql-demo-01

SQL Server 16.0.4135.4onprem2026-10-22 09:30Read-only analysisAnálise somente leitura

GradeNota
D55/100
Weighted by severityPonderada pela severidade
CoverageCobertura
83%
10 of 12 applicable rules ran10 de 12 regras aplicáveis executadas
FindingsAchados
5
3 critical or high3 críticos ou altos
No dataSem dados
2
Rules that could not runRegras que não puderam rodar

Points of attentionPontos de atenção

Databases with missing or old backupsBancos com backup ausente ou antigoCheck the backup jobs for these databases and run a manual backup now. In FULL recovery, schedule log backups too.Verifique os jobs de backup desses bancos e faça um backup manual agora. Em recovery FULL, agende também backups de log.Databases without a recent clean DBCC CHECKDBBancos sem DBCC CHECKDB recente e sem errosSchedule DBCC CHECKDB (WITH NO_INFOMSGS, ALL_ERRORMSGS) at least weekly, or on a restored copy if the window is short.Agende DBCC CHECKDB (WITH NO_INFOMSGS, ALL_ERRORMSGS) pelo menos semanalmente, ou numa cópia restaurada se a janela for curta.The instance spends a lot of time waiting on one resourceA instância passa muito tempo esperando por um recursoStart with the top row. The meaning column says which resource to look at; the rule's documentation page lists the usual causes for each wait.Comece pela primeira linha. A coluna de significado diz qual recurso investigar; a página da regra na documentação lista as causas comuns de cada espera.Instance settings left at defaults that hurt performanceConfigurações da instância no padrão que prejudicam o desempenhoReview each setting with sp_configure, starting with max server memory. Change one at a time and observe.Revise cada configuração com sp_configure, começando pelo max server memory. Mude uma por vez e observe.High-impact missing indexesÍndices ausentes de alto impactoTreat each row as a lead, not a command. Compare it with the existing indexes on the table, merge similar suggestions and test the index before creating it in production.Trate cada linha como pista, não como ordem. Compare com os índices que já existem na tabela, junte sugestões parecidas e teste o índice antes de criar em produção.

FindingsAchados 5

Finding 1 of 5Achado 1 de 5 · CriticalCrítica ConfirmedConfirmado

Databases with missing or old backupsBancos com backup ausente ou antigo

databaserecovery_modellast_fulllast_difflast_logproblem
salesFULL2026-10-12 23:10NULL2026-10-12 23:40full/diff too old
inventoryFULL2026-10-21 23:052026-10-21 23:302026-10-21 02:15log backup too old

What it meansO que significa

A failure or mistake on these databases may lose more data than you expect, or be unrecoverable.Uma falha ou erro nesses bancos pode perder mais dados do que você espera, ou não ter recuperação.

Recommended actionAção recomendada

Check the backup jobs for these databases and run a manual backup now. In FULL recovery, schedule log backups too.Verifique os jobs de backup desses bancos e faça um backup manual agora. Em recovery FULL, agende também backups de log.

CaveatRessalva: Based on msdb history on this instance. Backups taken by external tools without msdb history are not visible.Baseado no histórico do msdb desta instância. Backups de ferramentas externas sem histórico no msdb não aparecem.

Source queryQuery de origem · Collected atColetado em 2026-10-22 09:30 UTC · 120ms
WITH b AS (
    SELECT database_name,
           MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS last_full,
           MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS last_diff,
           MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS last_log
    FROM msdb.dbo.backupset
    WHERE is_copy_only = 0
    GROUP BY database_name
)
SELECT d.name                AS [database],
       d.recovery_model_desc AS recovery_model,
       b.last_full,
       b.last_diff,
       b.last_log,
       CASE
           WHEN b.last_full IS NULL THEN 'no full backup'
           WHEN ISNULL(b.last_diff, b.last_full) < DATEADD(hour, -{{full_max_hours}}, GETDATE())
                AND b.last_full < DATEADD(hour, -{{full_max_hours}}, GETDATE()) THEN 'full/diff too old'
           ELSE 'log backup too old'
       END AS problem
FROM sys.databases d
LEFT JOIN b ON b.database_name = d.name
WHERE d.database_id <> 2               -- tempdb
  AND d.state_desc = 'ONLINE'
  AND d.source_database_id IS NULL     -- snapshots
  AND (
        b.last_full IS NULL
     OR (ISNULL(b.last_diff, b.last_full) < DATEADD(hour, -{{full_max_hours}}, GETDATE())
         AND b.last_full < DATEADD(hour, -{{full_max_hours}}, GETDATE()))
     OR (d.recovery_model_desc <> 'SIMPLE' AND d.name <> 'model'
         AND ISNULL(b.last_log, '19000101') < DATEADD(hour, -{{log_max_hours}}, GETDATE()))
  )
ORDER BY d.name;
Finding 2 of 5Achado 2 de 5 · HighAlta ConfirmedConfirmado

Databases without a recent clean DBCC CHECKDBBancos sem DBCC CHECKDB recente e sem erros

databaselast_good_checkdbdays_agocreate_date
sales2026-08-30 01:00532021-03-02
reportingNULLNULL2025-11-18

What it meansO que significa

Corruption can sit unnoticed for weeks and end up in every backup, leaving nothing clean to restore.Uma corrupção pode passar semanas sem ser notada e entrar em todos os backups, sem deixar nada limpo para restaurar.

Recommended actionAção recomendada

Schedule DBCC CHECKDB (WITH NO_INFOMSGS, ALL_ERRORMSGS) at least weekly, or on a restored copy if the window is short.Agende DBCC CHECKDB (WITH NO_INFOMSGS, ALL_ERRORMSGS) pelo menos semanalmente, ou numa cópia restaurada se a janela for curta.

CaveatRessalva: Reads LastGoodCheckDbTime, which only records runs that finished without errors. Databases created in the last days are skipped.Lê o LastGoodCheckDbTime, que só registra execuções concluídas sem erros. Bancos criados nos últimos dias são ignorados.

Source queryQuery de origem · Collected atColetado em 2026-10-22 09:30 UTC · 120ms
SELECT d.name AS [database],
       NULLIF(CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime), '19000101') AS last_good_checkdb,
       DATEDIFF(day, NULLIF(CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime), '19000101'), GETDATE()) AS days_ago,
       d.create_date
FROM sys.databases d
WHERE d.database_id <> 2                -- tempdb
  AND d.state_desc = 'ONLINE'
  AND d.source_database_id IS NULL      -- snapshots
  AND d.create_date < DATEADD(day, -{{max_days}}, GETDATE())
  AND ISNULL(CAST(DATABASEPROPERTYEX(d.name, 'LastGoodCheckDbTime') AS datetime), '19000101') < DATEADD(day, -{{max_days}}, GETDATE())
ORDER BY d.name;
Finding 3 of 5Achado 3 de 5 · HighAlta HintIndício

The instance spends a lot of time waiting on one resourceA instância passa muito tempo esperando por um recurso

meaningmeaningwait_typeshare_pctwait_s_per_houravg_wait_ms
Disk reads (data pages not in memory)Leitura de disco (páginas fora da memória)PAGEIOLATCH_SH41.7812.418.3
Parallel query coordinationCoordenação de consultas paralelasCXPACKET22.94463.1

What it meansO que significa

Waits are where query time goes when it isn't running. A dominant wait points straight at the bottleneck (disk, locks, CPU, memory).As esperas mostram para onde vai o tempo das consultas quando elas não estão executando. Uma espera dominante aponta direto para o gargalo (disco, bloqueios, CPU, memória).

Recommended actionAção recomendada

Start with the top row. The meaning column says which resource to look at; the rule's documentation page lists the usual causes for each wait.Comece pela primeira linha. A coluna de significado diz qual recurso investigar; a página da regra na documentação lista as causas comuns de cada espera.

CaveatRessalva: Totals accumulate since the last restart, so they show the long-term profile, not what is happening right now. Only deltas over time show the present.Os totais acumulam desde o último restart, então mostram o perfil de longo prazo, não o que acontece agora. Só diferenças ao longo do tempo mostram o presente.

Source queryQuery de origem · Collected atColetado em 2026-10-22 09:30 UTC · 120ms
-- Only waits with a clear meaning are counted; idle and background waits never reach the report.
WITH meaning (pattern, cat_en, cat_pt) AS (
    SELECT * FROM (VALUES
        ('PAGEIOLATCH[_]%',         'Disk: reading data pages',                     'Disco: leitura de páginas de dados'),
        ('WRITELOG',                'Disk: transaction log writes',                 'Disco: escrita no log de transações'),
        ('IO[_]COMPLETION',         'Disk: other I/O',                              'Disco: outros I/O'),
        ('LCK[_]M[_]%',             'Blocking: waiting for locks',                  'Bloqueio: esperando locks'),
        ('PAGELATCH[_]%',           'Page contention in memory (often TempDB)',     'Disputa de páginas em memória (geralmente TempDB)'),
        ('SOS[_]SCHEDULER[_]YIELD', 'CPU pressure',                                 'Pressão de CPU'),
        ('CXPACKET',                'Parallelism',                                  'Paralelismo'),
        ('CXCONSUMER',              'Parallelism',                                  'Paralelismo'),
        ('RESOURCE[_]SEMAPHORE',    'Queries waiting for memory grants',            'Consultas esperando memória'),
        ('THREADPOOL',              'Out of worker threads',                        'Falta de threads de trabalho'),
        ('ASYNC[_]NETWORK[_]IO',    'Application not reading results fast enough',  'Aplicação lendo resultados devagar'),
        ('HADR[_]SYNC[_]COMMIT',    'Synchronous Availability Group commit',        'Commit síncrono do Availability Group')
    ) v (pattern, cat_en, cat_pt)
),
c AS (
    SELECT m.cat_en, MAX(m.cat_pt) AS cat_pt, SUM(ws.wait_time_ms) AS ms, SUM(ws.waiting_tasks_count) AS tasks,
           MAX(ws.wait_type) AS example
    FROM sys.dm_os_wait_stats ws
    JOIN meaning m ON ws.wait_type LIKE m.pattern
    WHERE ws.wait_time_ms > 0
    GROUP BY m.cat_en
),
t AS (SELECT SUM(ms) AS total FROM c),
up AS (SELECT DATEDIFF(second, sqlserver_start_time, SYSDATETIME()) / 3600.0 AS hours FROM sys.dm_os_sys_info)
SELECT c.cat_en AS [meaning@en],
       c.cat_pt AS [meaning@pt-BR],
       c.example AS wait_type,
       CAST(c.ms * 100.0 / t.total AS decimal(5, 1)) AS share_pct,
       CAST(c.ms / 1000.0 / NULLIF(up.hours, 0) AS decimal(14, 1)) AS wait_s_per_hour,
       CAST(c.ms * 1.0 / NULLIF(c.tasks, 0) AS decimal(14, 1)) AS avg_wait_ms,
       CASE WHEN c.cat_en IN ('Out of worker threads', 'Queries waiting for memory grants') THEN 'confirmed' ELSE 'hint' END AS _confidence
FROM c CROSS JOIN t CROSS JOIN up
WHERE c.ms * 100.0 / t.total >= {{min_share_pct}}
  AND c.ms / 1000.0 / NULLIF(up.hours, 0) >= {{min_wait_s_per_hour}}
ORDER BY c.ms DESC;
Finding 4 of 5Achado 4 de 5 · MediumMédia HintIndício

Instance settings left at defaults that hurt performanceConfigurações da instância no padrão que prejudicam o desempenho

settingcurrent_valuesuggestedhost
max server memory (MB)21474836472621432768 MB RAM
cost threshold for parallelism55016 CPUs

What it meansO que significa

Default memory can starve the OS; default parallelism settings make small queries go parallel and fight for CPU.A memória padrão pode sufocar o sistema operacional; o paralelismo padrão faz consultas pequenas rodarem em paralelo e disputarem CPU.

Recommended actionAção recomendada

Review each setting with sp_configure, starting with max server memory. Change one at a time and observe.Revise cada configuração com sp_configure, começando pelo max server memory. Mude uma por vez e observe.

CaveatRessalva: Recommendations are common starting points, not universal rules. Hosts running other services may need different values.As recomendações são pontos de partida comuns, não regras universais. Hosts com outros serviços podem precisar de outros valores.

Source queryQuery de origem · Collected atColetado em 2026-10-22 09:30 UTC · 120ms
WITH c AS (SELECT name, CAST(value_in_use AS bigint) AS v FROM sys.configurations),
     s AS (SELECT cpu_count, physical_memory_kb / 1024 AS ram_mb FROM sys.dm_os_sys_info)
SELECT 'max server memory (MB)' AS setting, CAST(c.v AS varchar(20)) AS current_value,
       CAST(CAST(s.ram_mb * 0.8 AS bigint) AS varchar(20)) AS suggested, CAST(s.ram_mb AS varchar(20)) + ' MB RAM' AS host
FROM c CROSS JOIN s WHERE c.name = 'max server memory (MB)' AND c.v >= 2147483647
UNION ALL
SELECT 'max degree of parallelism', CAST(c.v AS varchar(20)), '8', CAST(s.cpu_count AS varchar(20)) + ' CPUs'
FROM c CROSS JOIN s WHERE c.name = 'max degree of parallelism' AND c.v = 0 AND s.cpu_count > {{maxdop_cpus}}
UNION ALL
SELECT 'cost threshold for parallelism', CAST(c.v AS varchar(20)), '50', CAST(s.cpu_count AS varchar(20)) + ' CPUs'
FROM c CROSS JOIN s WHERE c.name = 'cost threshold for parallelism' AND c.v = 5
UNION ALL
SELECT 'optimize for ad hoc workloads', CAST(c.v AS varchar(20)), '1', NULL
FROM c WHERE c.name = 'optimize for ad hoc workloads' AND c.v = 0;
Finding 5 of 5Achado 5 de 5 · MediumMédia HintIndício

High-impact missing indexesÍndices ausentes de alto impacto

databasetableequality_columnsinequality_columnsincluded_columnsusesest_impact_pctimprovementlast_user_seek
sales[sales].[dbo].[orders][customer_id][order_date][total]4821093.418402212026-10-22 09:12

What it meansO que significa

The optimizer recorded queries that would run much cheaper with an index that doesn't exist. They read more pages and hold locks longer than needed.O otimizador registrou consultas que ficariam bem mais baratas com um índice que não existe. Elas leem mais páginas e seguram locks por mais tempo que o necessário.

Recommended actionAção recomendada

Treat each row as a lead, not a command. Compare it with the existing indexes on the table, merge similar suggestions and test the index before creating it in production.Trate cada linha como pista, não como ordem. Compare com os índices que já existem na tabela, junte sugestões parecidas e teste o índice antes de criar em produção.

CaveatRessalva: Always a hint. The DMV ignores existing similar indexes, suggests overlapping indexes, and is cleared on restart.Sempre um indício. A DMV ignora índices parecidos que já existem, sugere índices sobrepostos e é zerada no restart.

Source queryQuery de origem · Collected atColetado em 2026-10-22 09:30 UTC · 120ms
SELECT TOP (20)
       DB_NAME(d.database_id) AS [database],
       d.statement AS [table],
       d.equality_columns,
       d.inequality_columns,
       d.included_columns,
       s.user_seeks + s.user_scans AS uses,
       CAST(s.avg_user_impact AS decimal(5, 1)) AS est_impact_pct,
       CAST(s.avg_total_user_cost * s.avg_user_impact * (s.user_seeks + s.user_scans) AS decimal(18, 0)) AS improvement,
       s.last_user_seek
FROM sys.dm_db_missing_index_details d
JOIN sys.dm_db_missing_index_groups g ON g.index_handle = d.index_handle
JOIN sys.dm_db_missing_index_group_stats s ON s.group_handle = g.index_group_handle
WHERE d.database_id > 4
  AND s.avg_user_impact >= {{min_impact_pct}}
  AND s.avg_total_user_cost * s.avg_user_impact * (s.user_seeks + s.user_scans) >= {{min_improvement}}
ORDER BY improvement DESC;

No dataSem dados 2

RuleRegraReasonMotivoRequired permissionPermissão necessária
SQL Agent jobs failingJobs do SQL Agent com falha
MSSQL-AGENT-001
The SELECT permission was denied on the object 'sysjobhistory', database 'msdb'.SQLAgentReaderRole on msdb
Unused or duplicate indexesÍndices não usados ou duplicados
MSSQL-UNUSEDIDX-001
skipped databases (no access): archiveVIEW SERVER STATE + VIEW ANY DEFINITION + CONNECT ANY DATABASE

PassedSem problemas 5

Baseline and trendsBaseline e tendências History and trends need continuous monitoring.Histórico e tendências exigem monitoramento contínuo. Try codeDBConheça o codeDB →