Pergunta

A minha memória está falhando comigo. Eu tenho uma tabela log de auditoria simples baseado em um gatilho:
ID int (identidade, PK)
Cliente int
Nome varchar (255)
Endereço varchar (255)
AuditDateTime datetime
AuditCode char (1)
Tem dados como este:
ID Cliente Nome Endereço AuditDateTime AuditCode 1 123 Bob 123 Internet Way 2009-07-17 13: 18: 06,353 I 2 123 Bob 123 Internet Way 2009-07-17 13: 19: 02,117 D 3 123 Jerry 123 Internet Way 2009-07-17 13: 36: 03,517 I 4 123 Bob 123 My Way Editado 2009-07-17 13: 36: 08,050 U 5 100 Arnold 100 SkyNet Way 2009-07-17 13: 36: 18,607 I 6 100 Nicky 100 de estrela 2009-07-17 13: 36: 25,920 U 7 110 Blondie 110 Another Way 2009-07-17 13: 36: 42,313 I 8 113 Sally 113 ainda uma outra maneira 2009-07-17 13: 36: 57,627 I

Qual seria a instrução select eficiente ser para obter todos os registros mais atuais entre a hora de início e fim FYI:?. I para inserir, D para apagar, e U para atualização
Estou faltando alguma coisa na tabela de auditoria? Meu próximo passo é criar uma tabela de auditoria que só registra mudanças, mas você pode extrair os registros mais recentes para o determinado período de tempo. Para a vida de mim eu não posso encontrá-lo em qualquer motor de busca facilmente. Ligações iria trabalhar muito. Obrigado pela ajuda.

Foi útil?

Solução

Outro (melhor?) Para manter o histórico de auditoria é usar um 'startDate' e coluna 'endDate' em vez de um auditDateTime e coluna AuditCode. Isso é muitas vezes a abordagem no rastreamento de Tipo 2 alterações (novas versões de uma linha) em armazéns de dados.

Isso permite selecionar mais diretamente as linhas atuais (ONDE endDate é NULL), e você não vai precisar de atualizações tratam de forma diferente do que inserções ou exclusões. Você simplesmente tem três casos:

  • Inserir: copiar a linha completa juntamente com uma data de início e data final NULL
  • Excluir: definir a data de término da linha atual existente (endDate é NULL)
  • Update: fazer um Excluir em seguida, insira

Seu selecione seria simplesmente:

select * from AuditTable where endDate is NULL

De qualquer forma, aqui está minha consulta para o seu 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

Referências

A cribsheet para armazéns de dados , mas tem uma seção boa em tipo 2 alterações (o que você deseja acompanhar)

página MSDN sobre data warehousing

Outras dicas

Ok, um par de coisas para as tabelas de log de auditoria.

Para a maioria das aplicações, queremos tabelas de auditoria a ser extremamente rápido na inserção.

Se o log de auditoria é verdadeiramente para diagnóstico ou por razões de auditoria muito irregulares, em seguida, os critérios de inserção mais rápida é fazer com que a mesa fisicamente ordenou em cima tempo de inserção.

E isto significa colocar o tempo de auditoria como a primeira coluna do índice agrupado, por exemplo.

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

Isto irá permitir a escolha consultas extremamente eficientes em cima AuditDateTime O (N log N) e S (1) inserções.

Se você deseja olhar para cima a sua tabela de auditoria em uma base por CustomerID, então você terá de compromisso.

Você pode adicionar um índice agrupado em cima (CustomerID, AuditDateTime), o que permitirá O (log n) de pesquisa de histórico de auditoria por cliente, no entanto, o custo será a manutenção desse índice sem cluster após a inserção - que a manutenção ser O (N log N) inversamente.

No entanto, que penalidade de tempo de inserção pode ser preferível a varredura da tabela (ou seja, O (n) Custo complexidade de tempo) que você terá que pagar se você não tiver um índice em CódigoDoCliente e esta é uma consulta regular que é realizado. Um O (n) lookup que bloqueia a tabela para o processo de escrita para uma consulta irregular pode bloquear-se escritores, por isso às vezes é do interesse dos escritores a ser um pouco mais lento se garantir que os leitores não vão estar bloqueando seus commits, porque os leitores precisam de varredura da tabela devido à falta de um índice bom para apoiá-los ....


A adição: se você está olhando para restringir a um determinado período de tempo, a coisa mais importante em primeiro lugar é o índice sobre AuditDateTime. E torná-lo agrupado como você está inserindo a fim AuditDateTime. Esta é a maior coisa que você pode fazer para tornar sua consulta eficiente desde o início.

Em seguida, se você está procurando a atualização mais recente para todos CustomerID de dentro de um determinado período de tempo, bem depois uma verificação completa dos dados, restringida por data de inserção, é necessário.

Você vai precisar fazer uma subconsulta na sua tabela de auditoria, entre o intervalo,

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

e, em seguida, incorporar em que a sua consulta de seleção adequada, por exemplo.

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

Outra abordagem é usar um sub selecione

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;

começar e terminar o tempo? por exemplo, como entre 01:00-03:00
ou iniciar e terminar data e hora? por exemplo como em 2009-07-17 13:36 a 2009-07-18 13:36

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top