Как лучше всего сохранить столбец LastUpdatedDate в SQL?
-
05-07-2019 - |
Вопрос
Предположим, у меня есть таблица базы данных, в которой есть столбец даты и времени последнего обновления или вставки.Что будет предпочтительнее:
- Попросите триггер обновить поле.
- Попросите программу, выполняющую вставку/обновление, установить это поле.
Первый вариант кажется самым простым, поскольку для этого мне даже не нужно перекомпилировать, но на самом деле это не так уж и важно.Кроме этого, мне трудно придумать какие-либо причины, чтобы сделать одно лучше другого.Какие-либо предложения?
Решение
Первый вариант может быть более надежным, поскольку база данных будет поддерживать поле. Это связано с возможными издержками использования триггеров.
Если бы в будущем вы могли записывать в эту таблицу другие приложения через свои собственные интерфейсы, я бы использовал триггер, чтобы вы не повторяли эту логику где-либо еще.
Если ваше приложение в значительной степени оно или другие приложения будут получать доступ к базе данных через один и тот же слой данных, то я бы избежал того кошмара, который триггеры могут вызвать и поместить логику прямо в ваш слой данных (SQL, ORM, хранимые процессы , так далее.). Р>
Конечно, вам нужно убедиться, что ваш источник времени (ваше приложение, компьютеры ваших пользователей, ваш SQL-сервер) точен в любом случае.
<Ч>Относительно того, почему я не люблю триггеры:
Возможно, я был опрометчив, называя их кошмаром. Как и все остальное, они уместны в меру. Если вы используете их для очень простых вещей, как это, я мог бы попасть на борт. Р>
Именно когда код триггера становится сложным (и дорогим), триггеры начинают вызывать множество проблем. Они являются скрытым налогом на каждый выполняемый вами запрос вставки / обновления / удаления (в зависимости от типа триггера). Если этот налог приемлем, то они могут быть подходящим инструментом для работы. Р>
Другие советы
Вы не упомянули 3. Используйте хранимую процедуру для обновления таблицы. Процедура может устанавливать временные метки по желанию. Р>
Возможно, это неосуществимо для вас, но я не видел, чтобы это упоминалось. Р>
Я бы сказал, триггер на тот случай, если кто-то использует что-то помимо вашего приложения для обновления таблицы, вы, вероятно, также захотите иметь LastUpdatedBy и использовать для этого SUSER_SNAME (), чтобы вы могли видеть, кто сделал обновление
Пока я использую СУБД, триггерам которой я доверяю, я всегда буду использовать опцию триггера. Это позволяет СУБД позаботиться о как можно большем количестве вещей, что, как правило, хорошо.
При любых обстоятельствах убедитесь, что столбец метки времени имеет правильное значение. Накладные расходы были бы незначительными. Р>
Единственное, что было бы против триггеров, это мобильность. Если это не проблема, я не думаю, что есть вопрос, в каком направлении идти.
Я сторонник хранимых процедур для всего. Ваш процесс обновления может содержать GETDATE () для столбца.
И мне не нравятся триггеры для такого рода обновлений. Отсутствие видимости триггеров приводит к путанице.
Для меня это звучит как бизнес-логика ... Я был бы более склонен поместить это в код. Позвольте базе данных управлять хранением данных ... Не больше и не меньше.
Триггеры - это благословение и проклятие. Р>
Благословение: вы можете использовать их для включения всех видов пользовательской проверки ограничений и управления данными без знания или изменений в бэкэнд-системах.
Проклятие: ты не знаешь, что происходит за твоей спиной. Проблемы / взаимные блокировки параллелизма дополнительными объектами, введенными в транзакции, которые изначально не ожидались. Фантомное поведение, включая изменения среды сеанса, ненадежные счета строк. Чрезмерное срабатывание условий .. дополнительные штрафы за горячую точку / производительность.
Ответ на этот вопрос (Обновление дат неявно (триггер) или явно (код)) обычно имеет большой вес в контексте. Например, если вы используете дату последнего изменения в качестве информационного поля, вы можете изменить ее только в том случае, если «пользователь» действительно вносит существенные изменения в строку по сравнению с автоматизированным процессом, который просто обновляет какой-то внутренний маркер, который не интересует пользователей. . р>
Если вы используете триггер для синхронизации изменений или у вас нет контроля над кодом, который выполняет триггер, это имеет гораздо больше смысла.
Мой совет по триггеру, используйте его, чтобы быть осторожным. Большинство систем позволяют фильтровать выполнение на основе операции и измененных полей. Правильное использование триггеров «до» и «после» может оказать существенное влияние на производительность.
Наконец, несколько систем способны выполнить один триггер для нескольких изменений (несколько строк, выполненных в транзакции), ваш код должен быть готов к тому, чтобы применить себя как массовое обновление для нескольких строк.
Обычно я бы сказал, делать это на стороне базы данных, но это зависит от вашего приложения. Если вы используете LINQ-to-SQL, вы можете просто установить поле как Timestamp, и ваш DAL будет использовать поле Timestamp для параллелизма. Он обрабатывает это для вас автоматически, поэтому повторение кода не является событием. Р>
Если вы пишете свой DAL самостоятельно, то я бы с большей вероятностью справился с этим на стороне базы данных, поскольку это делает написание пользовательских интерфейсов гораздо более гибким - хотя, я бы, вероятно, сделал это в хранимой процедуре, которая имеет " общедоступный " доступ и таблицы заблокированы - вам не нужно, чтобы какой-либо клоун приходил и обходил вашу хранимую процедуру, записывая непосредственно в таблицы ... если вы не планируете сделать свой DAL автономным компонентом, который любое будущее приложение должно использовать для доступа к базы данных, в этом случае вы можете закодировать ее непосредственно в DAL - конечно, вы должны делать это только в том случае, если вы можете гарантировать, что все, кто обращается к базе данных, делают это через ваш компонент DAL.
Если вы хотите разрешить " общедоступные " доступ к базе данных для вставки в таблицы, тогда вам придется использовать триггер, потому что в противном случае любой может вставить / обновить одно поле в таблице, а обновленное поле никогда не будет обновлено.
Я хотел бы сохранить дату в базе данных, т. е. триггер, хранимую процедуру и т. д. В большинстве ваших приложений, управляемых базой данных, пользовательское приложение не будет единственным средством, с помощью которого бизнес-пользователи получают данные , Есть инструменты отчетности, выдержки, пользовательский SQL и т. Д. Кроме того, администратор базы данных вносит обновления и исправления, для которых приложение также не будет указывать дату. Р>
Но, честно говоря, причина № 1, по которой я бы не делал этого из приложения, заключается в том, что вы не можете контролировать дату / время на клиентском компьютере. Они могут откатить его назад, чтобы получить больше дней на пробную лицензию, или просто захотеть сделать что-то плохое для вашей программы.
Вы можете сделать это без триггера, если ваша база данных поддерживает значения по умолчанию для полей.Например, в SQL Server 2005 у меня есть таблица с полем, созданным следующим образом:
create table dbo.Repository
(
...
last_updated datetime default getdate(),
...
)
тогда код вставки просто исключает это поле из списка полей вставки.
Я забыл, что это сработало только для первой вставки - у меня также есть триггер обновления, чтобы обновить поля даты и поместить копию обновленной записи в мою таблицу истории - которую я бы опубликовал...но редактор продолжает выдавать ошибки в моем коде...
Окончательно:
create trigger dbo.Repository_Upd on dbo.Repository instead of update
as
--**************************************************************************
-- Trigger: Repository_Upd
-- Author: Ron Savage
-- Date: 09/28/2008
--
-- Description:
-- This trigger sets the last_updated and updated_by fields before the update
-- and puts a copy of the updated row into the Repository_History table.
--
-- Modification History:
-- Date Init Comment
-- 10/22/2008 RS Blocked .prm files from updating the history as they
-- get updated every time the cfg file is run.
-- 10/21/2008 RS Updated the insert into the history table to use the
-- d.last_updated field from the Repository table rather
-- than getdate() to avoid micro second differences.
-- 09/28/2008 RS Created.
--**************************************************************************
begin
--***********************************************************************
-- Update the record but fill in the updated_by, updated_system and
-- last_updated date with current information.
--***********************************************************************
update cr set
cr.filename = i.filename,
cr.created_by = i.created_by,
cr.created_system = i.created_system,
cr.create_date = i.create_date,
cr.updated_by = user,
cr.updated_system = host_name(),
cr.last_updated = getdate(),
cr.content = i.content
from
Repository cr
JOIN Inserted i
on (i.config_id = cr.config_id);
--***********************************************************************
-- Put a copy in the history table
--***********************************************************************
declare @extention varchar(3);
select @extention = lower(right(filename,3)) from Inserted;
if (@extention <> 'prm')
begin
Insert into Repository_History
select
i.config_id,
i.filename,
i.created_by,
i.created_system,
i.create_date,
user as updated_by,
host_name() as updated_system,
d.last_updated,
d.content
from
Inserted i
JOIN Repository d
on (d.config_id = i.config_id);
end
end
Рон