Триггеры базы данных

Раньше я никогда не был поклонником использования триггеров для таблиц базы данных. Для меня они всегда представляли некую «магию», которая должна была произойти на стороне базы данных, вдали от контроля кода моего приложения. Я также хотел ограничить объем работы, которую должна была выполнять БД, поскольку это обычно общий ресурс, и я всегда предполагал, что триггеры могут быть дорогими в сценариях с высокой нагрузкой.

Тем не менее, я нашел пару случаев, когда было целесообразно использовать триггеры (по крайней мере, на мой взгляд, они имели смысл). Однако недавно я оказался в ситуации, когда мне иногда нужно было «обойти» триггер. Я чувствовал себя действительно виноватым из-за того, что мне пришлось искать способы сделать это, и я все еще думаю, что лучший дизайн базы данных устранит необходимость в этом обходе. К сожалению, эта БД используется несколькими приложениями, некоторые из которых поддерживаются очень неохотной командой разработчиков, которая кричала бы об изменениях схемы, так что я застрял.

Каковы общие мнения о триггерах? Любите их? Ненавижу их? Думаете, они служат определенной цели в некоторых сценариях? Считаете ли вы, что необходимость обойти триггер означает, что вы «делаете это неправильно»?

Ответов (12)

Решение

Триггеры обычно используются неправильно, вносят ошибки, поэтому их следует избегать. Никогда не создавайте триггер для проверки ограничений целостности, пересекающий строки в таблице (например, «средняя зарплата по отделам не может превышать X»).

Том Кайт , вице-президент Oracle, указал, что он предпочел бы удалить триггеры как функцию базы данных Oracle из-за их частой роли в возникновении ошибок. Он знает, что это всего лишь сон, и триггеры здесь, чтобы остаться, но если бы он мог, он бы удалил триггеры из Oracle, он бы это сделал (вместе с предложением WHEN OTHERS и автономными транзакциями).

Можно ли правильно использовать триггеры? Абсолютно.

Проблема в том, что они используются неправильно во многих случаях, поэтому я был бы готов отказаться от любой предполагаемой выгоды только для того, чтобы избавиться от злоупотреблений (и ошибок), вызванных ими. - Том Кайт

Честно говоря, это единственный раз, когда я использую триггеры для имитации уникального индекса, которому разрешено иметь NULL, что не учитывается в уникальности.

Я лично не фанат. Я буду использовать их, но только когда обнаружу узкое место в коде, которое можно устранить, переместив действия в триггер. Как правило, я предпочитаю простоту, и один из способов сохранить простоту - хранить логику в одном месте - в приложении. Я также работал на работах, где доступ очень разрознен. В таких средах чем больше кода я упаковываю, тем больше людей мне нужно привлекать даже для самых простых исправлений.

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

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

Обратной стороной триггеров является то, что их может вызывать любое действие; это тоже сила - никто не собирается портить целостность системы своей некомпетентностью.

В противоположность этому, разрешение доступа к базе данных только через хранимые процедуры и представления по-прежнему разрешает доступ через бэкдор к разрешениям. Пользователям с достаточными разрешениями доверяют, что они не нарушат целостность базы данных, все остальные используют хранимые процедуры.

Что касается сокращения объема работы: базы данных потрясающе эффективны, когда им не приходится иметь дело с внешним миром; вы будете действительно удивлены, насколько даже переключение процессов вредит производительности. Это еще один положительный момент хранимых процедур: вместо дюжины обращений к базе данных (и всех связанных циклических обращений) есть один.

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

Бизнес-логика должна куда-то идти, и в структуру базы данных встроено множество подразумеваемых доменных правил - отношения, ограничения и так далее - это попытка кодифицировать бизнес-правила, например, говоря, что у пользователя может быть только один пароль. Учитывая, что вы начали переносить бизнес-правила на сервер базы данных, установив эти отношения и т. Д., Где вы проводите черту? Когда база данных откажется от ответственности за целостность данных и начнет доверять вызывающим приложениям и пользователям базы данных, чтобы все исправить? Хранимые процедуры с этими встроенными в них правилами могут передать большую политическую власть в руки администраторов баз данных. Все сводится к тому, сколько уровней будет существовать в вашей n-уровневой архитектуре; если есть уровень представления, бизнеса и данных, где разделение между бизнесом и данными? Какие преимущества добавляет бизнес-уровень? Будете ли вы запускать бизнес-уровень на сервере базы данных в качестве хранимых процедур?

Да, я думаю, что необходимость обхода триггера означает, что вы «делаете это неправильно»; в этом случае триггер не для вас.

введите описание изображения здесь

Общий вентилятор,

но на самом деле нужно использовать его экономно, когда,

  • Необходимо поддерживать согласованность (особенно, когда таблицы измерений используются на складе, и нам необходимо связать данные в таблице фактов с их правильным измерением. Иногда правильная строка в таблице измерений может быть очень дорогостоящей для вычисления, поэтому вам нужен ключ Чтобы быть записанным прямо в таблицу фактов, один хороший способ поддерживать эту «связь» - использовать триггер.

  • Необходимо регистрировать изменения (например, в таблице аудита полезно знать, какой пользователь @@ сделал изменение и когда оно произошло)

Некоторые СУБД, такие как sql server 2005, также предоставляют вам триггеры для операторов CREATE / ALTER / DROP (чтобы вы могли знать, кто создал какую таблицу, когда, какой столбец, когда и т. Д.)

Честно говоря, используя триггеры в этих трех сценариях, я не понимаю, зачем вам вообще нужно их «отключать».

Я впервые использовал триггеры пару недель назад. Мы перешли на производственный сервер с SQL 2000 на SQL 2005 и обнаружили, что драйверы по-разному ведут себя с полями NText (сохраняя большой XML-документ), отбрасывая последний байт. Я использовал триггер в качестве временного исправления, чтобы добавить дополнительный фиктивный байт (пробел) в конец данных, решая нашу проблему до тех пор, пока не будет найдено правильное решение.

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

Я обнаруживаю, что обхожу триггеры при массовом импорте данных. Считаю это оправданным в таких обстоятельствах.

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

В общем, я бы проголосовал за «в некоторых сценариях они служат определенной цели». Я всегда нервничаю из-за последствий для производительности.

Триггеры могут быть очень полезны. Они также могут быть очень опасными. Я думаю, что они подходят для задач по уборке дома, таких как заполнение данных аудита (созданных, измененной даты и т. Д.), А в некоторых базах данных могут использоваться для ссылочной целостности.

Но я не большой поклонник добавления в них большого количества бизнес-логики. Это может сделать поддержку проблематичной, потому что:

  • это дополнительный уровень кода для исследования
  • иногда, как узнал OP, когда вам нужно исправить данные, триггер может делать что-то с предположением, что изменение данных всегда происходит через директиву приложения, а не от разработчика или администратора баз данных, исправляющих проблему, или даже от другого приложение

Что касается необходимости обхода триггера, чтобы что-то сделать, это может означать, что вы делаете что-то не так, или это может означать, что триггер делает что-то не так.

Общее правило, которое я использую для триггеров, - делать их легкими, быстрыми, простыми и максимально неинвазивными.

Я работаю с веб-приложениями и приложениями winforms на C# и страстно НЕНАВИЖУ триггеры. Я никогда не сталкивался с ситуацией, когда я мог бы оправдать использование триггера перемещением этой логики на бизнес-уровень приложения и репликацией там логики триггера.

Я не занимаюсь никакой работой с типами DTS или чем-то подобным, поэтому могут быть некоторые варианты использования триггера там, но если кто-то из моих команд скажет, что они могут захотеть использовать триггер, им лучше подготовить свои аргументы. потому что я отказываюсь стоять в стороне и позволяю добавлять триггеры в любую базу данных, над которой я работаю.

Некоторые причины, по которым мне не нравятся триггеры:

  • Они переносят логику в базу данных. Как только вы начнете это делать, вы просите мир боли, потому что вы теряете свою отладку, безопасность времени компиляции, свой логический поток. Это все под гору.
  • Реализуемая ими логика никому не видна.
  • Не все движки баз данных поддерживают триггеры, поэтому ваше решение создает зависимости от движков баз данных.

Я уверен, что могу придумать и другие причины, но только их достаточно, чтобы я не использовал триггеры.

Что касается сокращения объема работы: базы данных потрясающе эффективны, когда им не приходится иметь дело с внешним миром; вы будете действительно удивлены, насколько даже переключение процессов вредит производительности. Это еще один положительный момент хранимых процедур: вместо дюжины обращений к базе данных (и всех связанных циклических обращений) есть один.

это немного не по теме, но вы также должны знать, что вы смотрите на это только с одного потенциального положительного момента.

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

Общее практическое правило: не используйте триггеры. Как упоминалось ранее, они добавляют накладные расходы и сложность, которых можно легко избежать, переместив логику с уровня БД.

Кроме того, в MS SQL Server триггеры запускаются один раз для каждой команды sql, а не для каждой строки. Например, следующий оператор sql выполнит триггер только один раз.

UPDATE tblUsers
SET Age = 11
WHERE State = 'NY'

Многие, в том числе и я, думали, что триггеры срабатывают для каждой строки, но это не так. Если у вас есть оператор sql, подобный приведенному выше, который может изменять данные более чем в одной строке, вы можете включить курсор для обновления всех записей, затронутых триггером. Вы можете видеть, как это можно очень быстро запутать.

«Никогда не создавайте триггер для проверки ограничений целостности, пересекающих строки в таблице» - я не могу согласиться. Вопрос помечен как «SQL Server», и предложения CHECK constraints в SQL Server не могут содержать подзапрос; Хуже того, реализация, похоже, имеет «жестко закодированное» предположение, что CHECK будет включать только одну строку, поэтому использование функции ненадежно. Итак, если мне нужно ограничение, которое на законных основаниях включает более одной строки - и хорошим примером здесь является упорядоченный первичный ключ в классической временной таблице `` допустимое время '', где мне нужно предотвратить перекрытие периодов для одного и того же объекта - как можно Я делаю это без триггера? Помните, что это первичный ключ, что-то, что нужно для обеспечения целостности данных, поэтому принудительное его применение где-либо еще, кроме СУБД, не может быть и речи.