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_icUrlTrackerinclui 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:
- Identificar conteúdo removido que ainda recebe tráfego e criar redirects para páginas atuais
- Detectar links externos que apontam para URLs antigos e contactar os sites de origem
- 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
- Extrair relatório de 404s (ver secção acima) e entregar à equipa UNICEF
- Fazer backup completo da base de dados (PITR + export manual)
- Executar primeiro no ambiente de qualidade (
uncdb-qual) - Validar o funcionamento completo do site em qualidade
- 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.