Skip to content

Excesso de Dados na Base de Dados#

Visão Geral#

A base de dados de produção contém uma quantidade anormal de dados acumulados que afetam diretamente a performance da aplicação. Os números abaixo foram confirmados com dados recentes de produção (exportados a 2026-04-14) e os scripts de limpeza foram testados com sucesso em ambiente local.


Tabelas Problemáticas#

1. icUrlTracker — 7.996.535 registos (~3.6 GB)#

Métrica Valor
Total de registos 7.996.535
Tamanho ~3.6 GB
Registos de 404 (logs) 7.994.631 (99,97%)
Redirects reais 1.904 (0,03%)
Valor normal < 10.000 registos

Esta tabela pertence ao pacote UrlTracker 3.15.0 para Umbraco. A esmagadora maioria dos registos são logs de pedidos 404 (Is404 = 1), não redirecionamentos. Apenas 1.904 registos são redirects reais que precisam de ser mantidos.

Consequências:

  • A gestão de redirecionamentos no backoffice do Umbraco está completamente inoperacional (timeouts)
  • Cada cold start precisa de carregar/processar esta tabela
  • O índice IX_icUrlTracker inclui todas as colunas, tornando-o enorme

Solução: Eliminar todos os registos com Is404 = 1. Isto mantém todos os 1.904 redirects reais intactos.


2. cmsPropertyData — 1.220.959 registos (~473 MB)#

Métrica Valor
Total de registos 1.220.959
Registos elimináveis 1.102.609 (90,3%)
Registos a manter (últimas 2 versões) 118.350 (9,7%)

Esta tabela armazena os valores de propriedades para cada versão de cada conteúdo. O Umbraco guarda todas as versões históricas indefinidamente.


3. cmsContentVersion — 77.923 registos#

Métrica Valor
Total de versões 77.923
Versões elimináveis 59.309 (76,1%)
Versões a manter (últimas 2 por nó) 18.614 (23,9%)

4. cmsPreviewXml — 69.142 registos (~360 MB)#

Cache XML de pré-visualização para cada versão. Após a limpeza de versões, reduz-se proporcionalmente.

5. LogApp — 1.964.123 registos (~859 MB)#

Tabela de logs aplicacionais que nunca foi limpa.

6. FormEditorFiles — 1.486 registos (~1 GB)#

Ficheiros de formulários. A avaliar se podem ser limpos.


Passo Prévio: Relatório de 404s para a Equipa UNICEF#

Executar ANTES da Limpeza

Antes de eliminar os registos de 404, é importante extrair um relatório dos URLs mais pedidos que resultam em erro 404. Este relatório deve ser entregue à equipa UNICEF para que possam decidir se pretendem criar redirecionamentos para os URLs mais relevantes.

-- Executar ANTES da limpeza
-- Exportar resultado para CSV e entregar à equipa UNICEF

-- Top 100 URLs mais pedidas que resultam em 404
SELECT TOP 100 
    OldUrl AS [URL],
    COUNT(*) AS [Pedidos],
    MAX(Inserted) AS [Ultimo Pedido],
    MIN(Inserted) AS [Primeiro Pedido]
FROM icUrlTracker
WHERE Is404 = 1
  AND OldUrl IS NOT NULL
  AND OldUrl != ''
GROUP BY OldUrl
ORDER BY COUNT(*) DESC;

-- Top 50 referrers (de onde vêm os pedidos 404)
SELECT TOP 50
    Referrer AS [Origem],
    COUNT(*) AS [Pedidos 404]
FROM icUrlTracker
WHERE Is404 = 1
  AND Referrer IS NOT NULL
  AND Referrer != ''
GROUP BY Referrer
ORDER BY COUNT(*) DESC;

Com base neste relatório, a equipa UNICEF pode:

  1. Identificar conteúdo removido que ainda recebe tráfego e criar redirects para páginas atuais
  2. Detectar links externos que apontam para URLs antigos e contactar os sites de origem
  3. Decidir quais 404s podem ser ignorados (bots, scans, URLs irrelevantes)

Os redirects podem ser criados no backoffice do Umbraco (após a limpeza da tabela) ou via regras no Web.config.


Scripts de Limpeza (Validados)#

Scripts Testados em Ambiente Local

Todos os scripts abaixo foram executados e validados numa cópia atualizada da base de dados de produção (Docker local, 2026-04-14). Zero erros, zero violações de chaves estrangeiras.

Antes de Executar em Produção

  1. Extrair relatório de 404s (ver secção acima) e entregar à equipa UNICEF
  2. Fazer backup completo da base de dados (PITR + export manual)
  3. Executar primeiro no ambiente de qualidade (uncdb-qual)
  4. Validar o funcionamento completo do site em qualidade
  5. Só depois executar em produção, numa janela de manutenção acordada

Ordem obrigatória de execução#

A ordem é importante devido às chaves estrangeiras entre tabelas:

cmsPropertyData → depende de → cmsContentVersion
cmsPreviewXml   → depende de → cmsContentVersion

Eliminar primeiro os filhos (PropertyData, PreviewXml), depois o pai (ContentVersion).


Passo 1: Limpar icUrlTracker (independente)#

-- Eliminar logs de 404 (99,97% da tabela)
-- Mantém TODOS os redirects reais (Is404 = 0)
-- Testado: 7.994.631 registos eliminados, 1.904 mantidos
DELETE FROM icUrlTracker WHERE Is404 = 1;

Passo 2: Limpar cmsPropertyData (eliminar PRIMEIRO — FK child)#

-- Eliminar dados de propriedades de versões antigas
-- Mantém apenas as últimas 2 versões por nó de conteúdo
-- Testado: 1.102.609 registos eliminados, 118.350 mantidos
DELETE pd FROM cmsPropertyData pd
WHERE pd.versionId IN (
    SELECT cv.VersionId FROM cmsContentVersion cv
    WHERE cv.VersionId NOT IN (
        SELECT TOP 2 cv2.VersionId 
        FROM cmsContentVersion cv2 
        WHERE cv2.ContentId = cv.ContentId 
        ORDER BY cv2.VersionDate DESC
    )
);

Passo 3: Limpar cmsPreviewXml (eliminar SEGUNDO — FK child)#

-- Eliminar cache de pré-visualização de versões antigas
-- Testado: 58.670 registos eliminados, 10.472 mantidos
DELETE px FROM cmsPreviewXml px
WHERE px.versionId IN (
    SELECT cv.VersionId FROM cmsContentVersion cv
    WHERE cv.VersionId NOT IN (
        SELECT TOP 2 cv2.VersionId 
        FROM cmsContentVersion cv2 
        WHERE cv2.ContentId = cv.ContentId 
        ORDER BY cv2.VersionDate DESC
    )
);

Passo 4: Limpar cmsContentVersion (eliminar TERCEIRO — FK parent)#

-- Eliminar versões antigas de conteúdo
-- Testado: 59.309 registos eliminados, 18.614 mantidos
DELETE FROM cmsContentVersion 
WHERE VersionId NOT IN (
    SELECT TOP 2 cv2.VersionId 
    FROM cmsContentVersion cv2 
    WHERE cv2.ContentId = cmsContentVersion.ContentId 
    ORDER BY cv2.VersionDate DESC
);

Passo 5: Limpar logs (independente)#

-- Limpar logs com mais de 3 meses
-- Nota: a coluna chama-se [Date], não DateCreated
-- Testado: 1.842.784 registos eliminados de LogApp, 77.615 de umbracoLog
DELETE FROM LogApp WHERE [Date] < DATEADD(month, -3, GETDATE());
DELETE FROM umbracoLog WHERE Datestamp < DATEADD(month, -3, GETDATE());

Passo 6: Reconstruir índices#

-- Reconstruir índices após a limpeza para recuperar espaço
ALTER INDEX ALL ON icUrlTracker REBUILD;
ALTER INDEX ALL ON cmsPropertyData REBUILD;
ALTER INDEX ALL ON cmsContentVersion REBUILD;
ALTER INDEX ALL ON cmsPreviewXml REBUILD;
ALTER INDEX ALL ON LogApp REBUILD;
ALTER INDEX ALL ON umbracoLog REBUILD;

Passo 7: Reiniciar o App Service#

Após a limpeza, reiniciar o App Service para limpar as caches em memória do Umbraco:

az webapp restart --name uncwebprd --resource-group unc-prd \
  --subscription 2e6c7ed6-c6f8-4058-901c-c3113a4df82a

Resultados Confirmados (Testes Locais)#

Tabela Antes Depois Redução
icUrlTracker 7.996.535 (3.6 GB) 1.904 99,97%
cmsPropertyData 1.220.959 (473 MB) 118.350 (103 MB) 90,3%
cmsContentVersion 77.923 (11 MB) 18.614 76,1%
cmsPreviewXml 69.142 (360 MB) 10.472 (110 MB) 84,8%
LogApp 1.964.123 (859 MB) 121.339 93,8%
umbracoLog 78.121 506 99,4%

Após a limpeza, a tabela icUrlTracker desaparece do top 10 de tabelas por tamanho.


Sobre Adicionar Índices#

Não são necessários novos índices. As tabelas Umbraco já têm índices adequados:

Tabela Índices Existentes
cmsContentVersion PK + IX_ContentId + IX_VersionId
cmsPropertyData PK + 3 nonclustered indexes
icUrlTracker PK + IX_icUrlTracker (covering index)
umbracoNode PK + 5 nonclustered indexes

Adicionar índices customizados poderia causar conflitos com o código do Umbraco e do pacote UrlTracker, que não os espera. A limpeza dos dados é suficiente para resolver os problemas de performance.