Стандарт SQL выберите текущие записи из вопроса журнала аудита

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

  •  16-09-2019
  •  | 
  •  

Вопрос

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

ID            int (идентификатор, PK)
Идентификатор клиента    инт               
Имя          переменный код (255)      
Адрес       переменный код (255)      
Дата проверки: Время дата - время          
Код проверки     символ (1)           


В нем есть такие данные, как это:

ID Идентификатор клиента Имя      Адрес             Дата проверки: Время          Код проверки  1  123        Боб       123 Интернет-способ    2009-07-17 13:18:06.353Я          2  123        Боб       123 Интернет-способ    2009-07-17 13:19:02.117D          3  123        Джерри     123 Интернет-способ    2009-07-17 13:36:03.517Я          4  123        Боб       123 Мой Отредактированный Способ   2009-07-17 13:36:08.050U          5  100        Арнольд    100 Способ Скайнета      2009-07-17 13:36:18.607Я          6  100        Ники     100 Звездный Путь        2009-07-17 13:36:25.920U          7  110        Блондиночка   110 Другой Способ     2009-07-17 13:36:42.313Я          8  113        Салли     113 Еще один Способ 2009-07-17 13:36:57.627Я         


Каким был бы эффективный оператор select для получения всех самых последних записей между временем начала и окончания? К ТВОЕМУ СВЕДЕНИЮ:I для вставки, D для удаления и U для обновления.

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

Это было полезно?

Решение

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

Это позволяет вам более непосредственно выбирать текущие строки (ГДЕ конечная дата равна НУЛЮ), и вам не нужно будет обрабатывать обновления иначе, чем вставки или удаления.У вас просто есть три случая:

  • Вставить:скопируйте полную строку вместе с начальной датой и НУЛЕВОЙ конечной датой
  • Удалить:установите конечную дату существующей текущей строки (конечная дата равна НУЛЮ).
  • Обновить:выполните Удаление, затем Вставьте

Ваш выбор был бы просто:

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 на хранилище данных

Другие советы

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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;

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top