Стандарт SQL выбрать текущие записи в вопросе журнала аудита - PullRequest
2 голосов
/ 18 июля 2009

Моя память подводит меня. У меня есть простая таблица журнала аудита на основе триггера:

ID int (удостоверение личности, PK)
CustomerID int
Имя varchar (255)
Адрес varchar (255)
AuditDateTime datetime
AuditCode char (1)


У него есть такие данные:

ID CustomerID Имя Адрес AuditDateTime AuditCode 1 123 Боб 123 Интернет-путь 2009-07-17 13: 18: 06.353 I 2 123 Боб 123 Интернет-путь 2009-07-17 13: 19: 02.117 D 3 123 Джерри 123 Интернет-путь 2009-07-17 13: 36: 03.517 I 4 123 Боб 123 Мой отредактированный путь 2009-07-17 13: 36: 08.050 U 5 100 Арнольд 100 SkyNet Way 2009-07-17 13: 36: 18.607 I 6 100 Ники 100 Star Way 2009-07-17 13: 36: 25,920 U 7 110 Blondie 110 Другой путь 2009-07-17 13: 36: 42,313 I 8 113 Салли 113 Еще один путь 2009-07-17 13: 36: 57,627 Я


Каким будет эффективный оператор select для получения всех самых последних записей между временем начала и окончания? К вашему сведению: I для вставки, D для удаления и U для обновления.

Я что-то упустил в таблице аудита? Следующим моим шагом будет создание таблицы аудита, в которой будут записываться только изменения, но вы можете извлечь самые последние записи за указанный период времени. Из-за моей жизни я не могу найти его в любой поисковой системе легко. Ссылки тоже будут работать. Спасибо за помощь.

Ответы [ 4 ]

2 голосов
/ 18 июля 2009

Хорошо, пара вещей для таблиц журнала аудита.

Для большинства приложений мы хотим, чтобы таблицы аудита были чрезвычайно быстрыми при вставке.

Если журнал аудита действительно предназначен для диагностики или по очень нерегулярным причинам аудита, то самым быстрым критерием вставки является физическое упорядочение таблицы по времени вставки.

И это означает, что в качестве первого столбца кластеризованного индекса следует указать время аудита, например,

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

Это позволит чрезвычайно эффективно выполнять запросы выбора при вставке AuditDateTime O (log n) и O (1).

Если вы хотите просмотреть свою таблицу аудита по каждому идентификатору клиента, вам придется пойти на компромисс.

Вы можете добавить некластеризованный индекс при (CustomerID, AuditDateTime), что позволит O (log n) просматривать историю аудита для каждого клиента, однако стоимость будет заключаться в обслуживании этого некластеризованного индекса при вставке - это обслуживание будет быть O (log n) наоборот.

Однако этот штраф за время вставки может быть предпочтительнее сканирования таблицы (то есть O (n) затрат на сложность времени), которые вам придется заплатить, если у вас нет индекса на CustomerID, и это обычный запрос, который выполняется. Поиск O (n), который блокирует таблицу для процесса записи для нерегулярного запроса, может блокировать авторов, поэтому иногда в интересах авторов быть немного медленнее, если он гарантирует, что читатели не будут блокировать свои коммиты, потому что читатели должны сканировать таблицы из-за отсутствия хорошего индекса для их поддержки ....


Добавление: если вы хотите ограничиться определенным таймфреймом, прежде всего важнее индекс AuditDateTime. И сделайте это кластеризованным, как вы вставляете в порядке AuditDateTime. Это самое важное, что вы можете сделать, чтобы ваш запрос был эффективен с самого начала.

Далее, если вы ищете самое последнее обновление для всех идентификаторов CustomerID за указанный промежуток времени, то после этого требуется полное сканирование данных, ограниченное датой вставки.

Вам нужно будет выполнить подзапрос к вашей таблице аудита, между диапазонами,

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

, а затем включите это в свой запрос select, например.

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
2 голосов
/ 18 июля 2009

Другой (лучший?) Метод для сохранения истории аудита состоит в том, чтобы использовать столбцы startDate и endDate вместо столбцов auditateme и AuditCode. Такой подход часто используется для отслеживания изменений типа 2 (новых версий строки) в хранилищах данных.

Это позволяет более непосредственно выбирать текущие строки (WHERE endDate равно NULL), и вам не нужно будет обрабатывать обновления иначе, чем вставки или удаления. У вас просто есть три случая:

  • Вставить: скопировать всю строку вместе с начальной датой и конечной датой NULL
  • Удалить: установить дату окончания существующей текущей строки (endDate is NULL)
  • Обновление: удалите, затем вставьте

Ваш выбор будет просто:

select * from AuditTable where endDate is NULL

В любом случае, вот мой запрос для вашей существующей схемы:

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

Ссылки

A таблица для хранилищ данных , но имеет хороший раздел об изменениях типа 2 (что вы хотите отслеживать)

Страница MSDN на хранилище данных

1 голос
/ 18 июля 2009

Другой подход заключается в использовании дополнительного выбора

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;
0 голосов
/ 18 июля 2009

время начала и окончания? например, между 1 и 3 часами утра
или время начала и окончания даты? например, как в 2009-07-17 13:36 до 2009-07-18 13: 36

...