estándar SQL seleccionar los registros actuales de una cuestión de registro de auditoría

StackOverflow https://stackoverflow.com/questions/1146004

  •  16-09-2019
  •  | 
  •  

Pregunta

Mi memoria me está fallando. Tengo una sencilla tabla de registro de auditoría basado en un disparador:
ID int (identidad, PK)
CustomerID int
Nombre varchar (255)
Dirección varchar (255)
AuditDateTime fecha y hora
AuditCode char (1)
Tiene datos como estos:
ID CustomerID Nombre Dirección AuditDateTime AuditCode 1 123 Bob 123 Internet Camino 2009-07-17 13: 18: 06,353 I 2 123 Bob 123 Internet Camino 2009-07-17 13: 19: 02,117 D 3 123 Jerry 123 Camino de Internet 2009-07-17 13: 36: 03,517 I 4 123 Pepe 123 Editado Mi Camino 2009-07-17 13: 36: 08,050 T 5 100 Arnold 100 SkyNet Camino 2009-07-17 13: 36: 18.607 I 6 100 Nicky 100 Star Way 2009-07-17 13: 36: 25.920 T 7 110 Blondie 110 Otra forma 2009-07-17 13: 36: 42.313 I 8 113 a Sally 113 embargo, otra manera 2009-07-17 13: 36: 57.627 I

¿Cuál sería la instrucción de selección eficiente sea para obtener todos los registros más actuales entre una hora de inicio y fin FYI:?. I para insertar D para borrar, y U para la actualización
Me estoy perdiendo algo en la tabla de auditoría? Mi siguiente paso es crear una tabla de auditoría que sólo registra los cambios, sin embargo, usted puede extraer los registros más recientes para el marco de tiempo dado. Porque la vida de mí no puedo encontrar en cualquier motor de búsqueda fácilmente. Enlaces funcionarían también. Gracias por la ayuda.

¿Fue útil?

Solución

Otro método (mejor?) Para mantener historial de auditoría es utilizar un 'startDate' y la columna 'endDate' en lugar de una columna auditDateTime y AuditCode. Esto es a menudo el enfoque de seguimiento Tipo 2 cambios (nuevas versiones de una fila) en los almacenes de datos.

Esto le permite seleccionar de forma más directa las filas actuales (DONDE endDate es NULL), y no será necesario para tratar las actualizaciones de manera diferente que las inserciones o eliminaciones. Simplemente hay tres casos:

  • Insertar: copiar la fila completa junto con una fecha de inicio y fecha de finalización NULL
  • Eliminar: establecer la fecha de finalización de la línea actual existente (endDate es NULL)
  • Actualización: hacer una eliminación a continuación, insertar

Su seleccione sería simplemente:

select * from AuditTable where endDate is NULL

De todos modos, aquí está mi consulta para su esquema existente:

declare @from datetime
declare @to datetime

select b.* from (
  select
    customerId
    max(auditdatetime) 'auditDateTime'
  from
    AuditTable
  where
    auditcode in ('I', 'U')
    and auditdatetime between @from and @to
  group by customerId
  having 
    /* rely on "current" being defined as INSERTS > DELETES */
    sum(case when auditcode = 'I' then 1 else 0 end) > 
    sum(case when auditcode = 'D' then 1 else 0 end)
) a
cross apply(
  select top 1 customerId, name, address, auditdateTime
  from AuditTable
  where auditdatetime = a.auditdatetime and customerId = a.customerId
) b

Referencias

cribsheet para almacenes de datos , pero tiene una buena sección sobre cambios de tipo 2 (lo que desea realizar un seguimiento)

almacenamiento de datos

Otros consejos

Bueno, un par de cosas para las mesas de registro de auditoría.

Para la mayoría de las aplicaciones, queremos tablas de auditoría a ser extremadamente rápida en la inserción.

Si el registro de auditoría es realmente para diagnóstico o por razones de auditoría muy irregulares, a continuación, los criterios de inserción más rápida es hacer que la mesa pidió físicamente al momento de la inserción.

Y esto significa poner el tiempo de auditoría como la primera columna del índice agrupado, por ejemplo.

create unique clustered index idx_mytable on mytable(AuditDateTime, ID)

Esto permitirá las consultas de selección extremadamente eficientes sobre AuditDateTime O (log n), y O (1) inserciones.

Si desea ver su tabla de auditoría en una base por CustomerID, entonces usted tendrá que hacer concesiones.

Puede añadir un índice no agrupado en (CustomerID, AuditDateTime), lo que permitirá O (log n) las operaciones de búsqueda de historial de auditoría por cliente, sin embargo, el costo será el mantenimiento de que el índice no agrupado después de la inserción - que la voluntad mantenimiento ser O (log n) a la inversa.

Sin embargo, eso penalización de tiempo de inserción puede ser preferible a la mesa de exploración (es decir, O (n) Coste complejidad de tiempo) que tendrá que pagar si usted no tiene un índice en CustomerID y esto es una consulta regular que es interpretado. Un O (n) las operaciones de búsqueda, que bloquea la tabla para el proceso de escritura de una consulta irregular puede bloquear hasta escritores, por lo que a veces se encuentra en los intereses de los escritores que sea un poco más lento si se garantiza que los lectores no van a estar bloqueando sus confirmaciones, porque los lectores necesitan exploración de la tabla debido a la falta de un buen índice para apoyarlos ....


Además: si usted está buscando para restringir a un período de tiempo dado, lo más importante en primer lugar es el índice sobre AuditDateTime. Y hacer que se agrupan como se va a insertar con el fin AuditDateTime. Esto es lo más grande que puede hacer para hacer su consulta eficiente desde el principio.

A continuación, si usted está buscando la actualización más reciente para todos los de CustomerID en un plazo determinado, bien a partir de entonces se requiere un análisis completo de los datos, restringido por fecha de inserción,.

Usted tendrá que hacer una sub consulta sobre tu tabla de auditoría, entre la gama,

select CustomerID, max(AuditDateTime) MaxAuditDateTime 
from AuditTrail 
where AuditDateTime >= @begin and Audit DateTime <= @end

y luego incorporar eso en su consulta de selección adecuado, por ejemplo.

select AuditTrail.* from AuditTrail
inner join 
    (select CustomerID, max(AuditDateTime) MaxAuditDateTime 
     from AuditTrail 
     where AuditDateTime >= @begin and Audit DateTime <= @end
    ) filtration
    on filtration.CustomerID = AuditTrail.CustomerID and 
       filtration.AuditDateTime = AuditTrail.AuditDateTime

Otro enfoque utiliza una sub seleccionar

select a.ID
       , a.CustomerID 
       , a.Name
       , a.Address
       , a.AuditDateTime
       , a.AuditCode
from   myauditlogtable a,
       (select s.id as maxid,max(s.AuditDateTime) 
                 from myauditlogtable as s 
                 group by maxid) 
        as subq
where subq.maxid=a.id;

de inicio y fin? por ejemplo como en entre 01 a.m.-03 a.m.
 o tiempo de inicio y fecha de finalización? por ejemplo como en 2009-07-17 13:36 a 13:36 2009-07-18

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top