Historial temporal en SQL Server: qué significa AS OF
Consulta versiones anteriores distinguiendo tiempo del sistema, vigencia del negocio, inicio de transacciones y necesidades adicionales de auditoría.
Cuando un precio pasa de 10 a 12, una tabla normal conserva el nuevo valor salvo que la aplicación registre historial. Una tabla temporal con versiones del sistema puede preservar automáticamente los estados anteriores. Ayuda en investigaciones, pero no responde de la misma manera a todas las preguntas históricas.
Distingue el valor registrado según el tiempo del sistema, cuándo debía entrar en vigor para el negocio y quién autorizó el cambio. Las tablas temporales atienden directamente la primera pregunta. Las otras requieren datos y procesos adicionales.
Observar versiones actuales y anteriores
El ejemplo usa SQL Server 2016 o posterior y crea tablas permanentes de práctica. Ejecútalo con autocommit y sin transacción exterior.
-- Use a disposable database, autocommit, and no enclosing transaction.
IF @@TRANCOUNT <> 0 THROW 50001, 'Use a separate practice connection.', 1;
CREATE TABLE dbo.PriceTemporalDemo (
ProductId int NOT NULL PRIMARY KEY,
Price decimal(12,2) NOT NULL,
ValidFrom datetime2(7) GENERATED ALWAYS AS ROW START NOT NULL,
ValidTo datetime2(7) GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
) WITH (SYSTEM_VERSIONING = ON (
HISTORY_TABLE = dbo.PriceTemporalDemoHistory
));
INSERT dbo.PriceTemporalDemo(ProductId, Price) VALUES (1, 10.00);
DECLARE @BeforeChange datetime2(7) = SYSUTCDATETIME();
WAITFOR DELAY '00:00:01';
UPDATE dbo.PriceTemporalDemo SET Price = 12.00 WHERE ProductId = 1;
SELECT ProductId, Price FROM dbo.PriceTemporalDemo WHERE ProductId = 1;
SELECT ProductId, Price, ValidFrom, ValidTo
FROM dbo.PriceTemporalDemo FOR SYSTEM_TIME AS OF @BeforeChange
WHERE ProductId = 1;
La consulta actual devuelve 12,00 y AS OF @BeforeChange devuelve 10,00. SQL Server busca versiones pertinentes en tablas actual e histórica mediante la sintaxis temporal, sin una unión manual.
El periodo utiliza datetime2 en UTC. AS OF selecciona una versión cuyo comienzo es anterior o igual al instante y cuyo final es posterior. El extremo superior está excluido. Utiliza un parámetro convertido correctamente a UTC, no una hora local con desfase supuesto.
La pausa solo separa los instantes del ejemplo. No pertenece al diseño productivo. Sin esa separación, una prueba breve puede hacer confusos los límites, especialmente si cambia la precisión.
La siguiente consulta expone los intervalos.
SELECT ProductId, Price, ValidFrom, ValidTo
FROM dbo.PriceTemporalDemo FOR SYSTEM_TIME ALL
WHERE ProductId = 1
ORDER BY ValidFrom, ValidTo;
Una actualización puede crear historial aunque asigne el mismo valor. Evita escrituras innecesarias cuando generan crecimiento costoso, sin eliminar modificaciones que sí tengan significado para el negocio.
Entender el reloj de la transacción
Los límites se basan en el inicio de la transacción, no en COMMIT. Una transacción larga puede introducir una versión cuyo inicio precede al momento en que otra conexión pudo verla confirmada. AS OF sigue esas reglas y no graba exactamente lo que observó cada lector concurrente.
Varias actualizaciones de una fila dentro de la misma transacción pueden generar versiones de duración cero. Las cláusulas temporales las excluyen; consultar directamente la tabla histórica puede revelar filas ausentes de FOR SYSTEM_TIME. No interpretes cualquier estado intermedio ausente como pérdida.
Si un precio introducido hoy debe aplicarse el próximo mes, guarda otra fecha o intervalo de vigencia del negocio. No intentes utilizar el periodo generado para representar esa planificación. Una corrección retroactiva también debe separar vigencia y momento de conocimiento.
Aplicar AS OF al mismo instante en varias tablas puede simplificar uniones históricas. Revisa también las tablas no temporales participantes. Un pedido antiguo unido al nombre actual de una categoría mutable mezcla épocas aunque parezca un informe histórico.
Operar el historial como datos reales
Calcula crecimiento según frecuencia de cambios y anchura de filas, no solo cantidad actual. Una tabla pequeña pero muy modificada puede generar mucho historial. Indexa la investigación concreta: buscar versiones de un producto difiere de reconstruir todo a una fecha.
La retención y limpieza necesitan decisiones explícitas. Un informe no puede recuperar versiones ya eliminadas. Documenta el horizonte disponible y supervisa el mecanismo apropiado de la versión instalada.
El historial temporal no sustituye copias ni auditoría inmutable. No registra automáticamente actor y motivo, y una operación privilegiada puede modificar la configuración. Conserva las atribuciones necesarias por separado y protege su acceso.
Planifica cambios de esquema y mantenimiento en tablas actual e histórica. SYSTEM_VERSIONING OFF deja un periodo sin captura automática. Al reactivarlo, indica la tabla histórica correcta para no comenzar otra accidentalmente.
Prueba actualizaciones, borrados, transacciones largas, múltiples cambios en una transacción e instantes exactos de transición. El diseño debe distinguir lo que el sistema registró de lo que el negocio quiso representar.
Referencias técnicas: Microsoft Learn: Query temporal data · Microsoft Learn: Temporal considerations.