SQL standard sélectionner les enregistrements en cours à partir d'une question du journal d'audit

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

  •  16-09-2019
  •  | 
  •  

Question

Ma mémoire me manque. J'ai une simple table de journal d'audit basé sur un déclencheur:
ID int (identité, PK)
CustomerID int
Nom varchar (255)
Adresse varchar (255)
AuditDateTime datetime
AuditCode char (1)
Il a des données comme ceci:
ID CustomerID Nom Adresse 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 Way Internet 2009-07-17 13: 36: 03,517 I 4 123 Bob 123 Ma Edited Way 2009-07-17 13: 36: 08,050 U 5 100 Arnold 100 SkyNet Way 17/07/2009 13: 36: 18,607 I 6 100 Nicky 100 Way étoile 17/07/2009 13: 36: 25,920 U 7 110 Blondie 110 Another Way 17/07/2009 13: 36: 42,313 I 8 113 Sally 113 Encore une autre façon 2009-07-17 13: 36: 57,627 I

Quelle serait l'instruction select efficace soit pour obtenir tous les enregistrements les plus courants entre un début et de fin Pour votre information:. I pour insérer, D pour supprimer, et U pour la mise à jour
Est-ce que je manque quelque chose dans la table d'audit? Ma prochaine étape est de créer une table de vérification qui enregistre uniquement les modifications, mais vous pouvez extraire les enregistrements les plus récents pour le laps de temps donné. Pour la vie de moi je ne peux pas trouver sur un moteur de recherche facilement. Liens travailleraient aussi. Merci pour l'aide.

Était-ce utile?

La solution

Une autre méthode (mieux?) Pour conserver l'historique de vérification est d'utiliser une colonne « startDate » et « endDate » plutôt que d'une colonne auditDateTime et AuditCode. Cela est souvent l'approche dans le suivi des changements de type 2 (nouvelles versions d'une ligne) dans les entrepôts de données.

Cela vous permet de sélectionner plus directement les lignes (où les endDate est NULL), et vous ne devez traiter les mises à jour différemment insertions ou suppressions. Il vous suffit de trois cas:

  • Insérer: copier la ligne complète avec une date de début et de fin NULL
  • Supprimer: définir la date de fin du courant existant ligne (endDate est NULL)
  • Mise à jour: faire Supprimer puis insérez

Votre sélection serait simplement:

select * from AuditTable where endDate is NULL

Quoi qu'il en soit, voici ma question pour votre schéma existant:

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

Références

cribsheet pour les entrepôts de données , mais il a une bonne section sur le type 2 changements (ce que vous voulez suivre)

La page MSDN sur entreposage

Autres conseils

Ok, deux choses pour les tables de journal d'audit.

Pour la plupart des applications, nous voulons des tables de vérification pour être extrêmement rapide lors de l'insertion.

Si le journal d'audit est vraiment pour le diagnostic ou pour des raisons de vérification très irrégulière, alors les critères d'insertion plus rapide est de rendre la table commandé physiquement sur le temps d'insertion.

Et cela signifie pour mettre le temps de vérification que la première colonne de l'index ordonné en clusters, par exemple.

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

Cela permettra de sélectionner les requêtes extrêmement efficaces sur AuditDateTime O (log n) et des insertions O (1).

Si vous souhaitez regarder votre table d'audit sur une base par CustomerID, alors vous aurez besoin de faire des compromis.

Vous pouvez ajouter un index non cluster sur (CustomerID, AuditDateTime), ce qui permettra à O (log n) recherche de l'histoire de l'audit par client, mais le coût sera le maintien de cet indice nonclustered lors de l'insertion - que l'entretien sera O (log n) inverse.

Cependant que la peine de temps d'insertion peut être préférable à l'analyse de la table (qui est, O (n) Coût de la complexité du temps) que vous devrez payer si vous ne disposez pas d'un index sur CustomerID et ceci est une requête régulière est effectuée. Un O (n) recherche qui verrouille la table pour le processus d'écriture pour une requête irrégulière peut bloquer les écrivains, il est parfois dans l'intérêt des écrivains d'être un peu plus lent si elle garantit que les lecteurs ne vont pas être bloquer leurs commits, parce que les lecteurs doivent scanner de table en raison du manque d'un bon indice pour les soutenir ....


Addition: si vous êtes à la recherche de limiter à un tout délai, la chose la plus importante donnée d'abord est l'indice sur AuditDateTime. Et faire comme vous regroupés insérez dans l'ordre AuditDateTime. C'est la plus grande chose que vous pouvez faire pour rendre votre requête efficace dès le début.

Ensuite, si vous êtes à la recherche de la dernière mise à jour pour tous les années CustomerID dans un laps de temps donné, bien après une analyse complète des données, limité par date d'insertion, est nécessaire.

Vous devez faire une sous-requête sur votre table d'audit, entre la plage,

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

puis incorporer dans votre requête de sélection appropriée, par exemple.

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

Une autre approche utilise un sous sélectionnez

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;

début et de fin? par exemple comme entre une heures-à-3 heures
 ou heure de début et date de fin? par exemple comme dans l'17/07/2009 13:36 à 13:36 18/07/2009

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top