Триггеры базы данных - плохая идея?
По моему опыту, они злы, потому что могут приводить к неожиданным побочным эффектам и их трудно отлаживать (особенно когда один триггер запускает другой). Часто разработчики даже не думают смотреть, есть ли триггер.
С другой стороны, похоже, что если у вас есть логика, которая должна выполняться каждый раз, когда в базе данных создается новый FOO, то наиболее надежным местом для его размещения является триггер вставки в таблицу FOO.
Единственный раз, когда мы используем триггеры, - это действительно простые вещи, такие как настройка ModifiedDate.
Вопрос закрыт для добавления ответов, но см. Также Безопасны ли триггеры базы данных для ограничений целостности таблиц?. (Спойлер: нет, это не так)
Этот сайт меня так бесит. Это вопрос типа БОЛЬШОЙ, но, как и многие другие, он закрыт, потому что людям не хватает воображения, чтобы принимать вопросы, не укладывающиеся в примитивный двоичный формат вопросов и ответов, которым они по какой-то инопланетной причине вынуждены следовать.
Бизнес-логика в триггере проблематична (зло, если хотите). Логика базы данных в триггере не вызывает проблем (целостность, ведение журнала).
Мне нравится полагаться на IDE для навигации по коду и понимания того, что происходит. Я не могу этого сделать, если половина логики находится в базе данных, а другая половина - в выбранном языке программирования. Вместо триггеров мне проще создать контроллер, через который должен проходить каждый запрос. Вместо этого могут быть применены все «триггеры».
@Quibblesome Я согласен. Этот вопрос имеет отношение к тому, над чем я работаю прямо сейчас. В то время как люди слишком легко закрывают вопросы по stackoverflow. Замечательно то, что эта страница появилась первой в моем поиске в Google, поэтому она по-прежнему доступна и считается актуальной.


Если есть побочные эффекты, это проблема по дизайну. В некоторых системах баз данных нет другой возможности установить поле автоинкремента, то есть для поля идентификатора первичного ключа.
Нет, на самом деле это хорошая идея. Если есть проблема с вашими конкретными триггерами, значит, вы делаете их неправильно, но обычно это означает, что проблема связана с вашей реализацией, нет - это концепция самих триггеров :-).
Мы часто используем триггеры, потому что они ставят специфические для СУБД действия под контроль той базы данных, которой они принадлежат. Пользователям СУБД не следует беспокоиться о подобных вещах. Целостность данных зависит от самой базы данных, нет приложений или пользователей, которые ее используют. Без ограничений, триггеров и других функций в базе данных, приложениям остается обеспечивать соблюдение правил, и для уничтожения данных требуется только одно мошенническое или ошибочное приложение / пользователь.
Например, без триггеров не было бы таких чудесных вещей, как автоматически сгенерированные столбцы, и вам пришлось бы обрабатывать функцию для каждой строки при их выборе. Это, вероятно, убьет производительность СУБД, гораздо лучше создать автоматически сгенерированный столбец во время вставки / обновления, поскольку это единственный раз, когда он изменяется.
Кроме того, отсутствие триггеров не позволит применять правила данных в СУБД, такие как предварительные триггеры, чтобы гарантировать, что столбцы имеют определенный формат. Обратите внимание, что это отличается от правил целостности данных, которые обычно представляют собой просто поиск внешнего ключа.
«обрабатывать функцию в каждой строке при их выборе». Для этой цели лучше использовать индекс, основанный на функциях, чем триггер.
Не обязательно, триггер, вероятно, сработает только при вставке или обновлении строки. Индекс на основе функций будет запускаться для каждого выбора. В зависимости от модели использования один, вероятно, лучше другого. Но ни один из них ВСЕГДА не лучше другого.
@tuinstoel: Я согласен с вашим утверждением некоторый того времени. Oracle, например, будет создавать индексы на основе функций только в том случае, если сможет доказать, что функция детерминирована. Иногда это просто невозможно доказать (например, если функция включает поиск из таблицы, даже если вы знать, что данные таблицы никогда не изменяются).
Основные проблемы с триггерами:
Это просто означает, что их нужно осторожно использовать в соответствующих обстоятельствах; который, по моему опыту, ограничивается проблемами реляционной целостности (иногда с большей степенью детализации, чем вы можете получить декларативно); и обычно не в деловых или транзакционных целях. YMMV.
В некоторых случаях это 2 преимущества.
«Скрытный» - отличное слово, да, хорошо сказано. Именно поэтому я стараюсь избегать их: слишком часто о них забывают или игнорируют. По моему личному опыту, повторное посещение триггеров часто сопровождается шлепком по лбу.
Вы можете встроить контекст в триггер. С помощью простого оператора if можно добиться очень многого.
@Nolan, я могу согласиться с тем, что Global приносит пользу - вот тогда они уместны. Но незаметно - мне труднее увидеть в этом преимущество. @tuinstoel, я не уверен, как триггер может иметь встроенный контекст, поскольку он не принимает аргументов.
Мне любопытна ваша цитата "никогда для бизнеса или в коммерческих целях", @le dorfier. Как вы думаете, почему это неуместно?
Несколько независимых причин, каждую из которых можно обсудить, но вместе я думаю, что они убедительны. 1. Бизнес-правила входят в BL вместе, где они доступны с должной степенью детализации для проверки пользовательского интерфейса и обработки исключений.
2. Триггеры глобальны и относительно неизменны. Бизнес-правила являются локальными и могут изменяться на местном уровне, которые не должны быть связаны с глобальными скрытыми триггерами. 3. Личный опыт. @Nunciato красиво сформулировал это выше.
Я был бы очень осторожен с использованием триггеров для создания чего-либо, связанного с реляционной целостностью. Около 90-99% этих триггеров, которые я видел, ожидают серьезной проблемы с целостностью данных. В остальных 1-10% это действительно произошло.
Глобальные, поэтому они хороши и необходимы для целостности данных и таких вещей, как аудит. Это не минус, это плюс.
На мой взгляд, триггеры - это путь к черту, беспорядок, ни один разработчик, которого я встречал, не знает, как с ними обращаться. Если вы думаете, что вам нужен триггер, подумайте еще раз! Тем не менее, разумное использование триггера может помочь вам избежать лишнего кода. Я удивлен, что никто не заметил триггеров "вместо" просмотров. Триггеры просмотра могут очень помочь с импортом-экспортом в инструменты, поддерживающие SQL, и предоставить средства для простой интеграции.
Итак, @ RobertŠevčík-Robajz, вы говорите, что все разработчики, которых вы знаете, некомпетентны?
@HLGEM, да. Они гуглили синтаксис, хорошо, но требуется гораздо больше, чтобы написать триггер, который поддерживает операцию набора и является эффективным. Думаю, дело не в том, что разработчики бесполезны, а в том, что эта тема не является их основной темой.
@ RobertŠevčík-Robajz, поскольку ни одно приложение, широко использующее базу данных, не обходится без специалиста по базам данных, который хорошо разбирается в базах данных, это не вина триггеров, что вы неправильно укомплектованы персоналом.
@HGLEM, согласен, должен быть специалист по проработке триггеров. Сценарий реальной жизни - нет. Сценарий из реальной жизни - дни, потраченные на попытки определить ошибку, связанную с забытым триггером. Сценарий из реальной жизни - логика триггера отчаянно внедряется в логику приложения, где ее можно легко реорганизовать и протестировать. Это реальная жизнь, с которой я имею дело, заставляет меня говорить «держись подальше от триггеров» ... это не ошибка триггеров, как и не вина камней, что окна разбиваются.
@ Роберт Шевчик - Робайз: А что делают ваши модульные тесты, когда сторонняя программа обращается к базе данных и вообще не обрабатывает, например TerminationDates подчиненных объектов? Или кто-то выполняет SQL-скрипт напрямую?
@Quandary, юнит-тесты устраивают вечеринку для сторонних разработчиков, но политики и списки контроля доступа не могут присутствовать, будучи полностью занятыми глупыми идеями сторонних разработчиков. Думаю, я сказал достаточно, пожалуйста, не обижайтесь, если в следующий раз я промолчу. Cheerio.
@dkretz Я планирую использовать триггер в своей таблице, чтобы сохранить целостность данных. Как вы думаете? ссылка: i.stack.imgur.com/tIOyp.png
Я бы сказал, что «триггеры скрытны» - одно из плохих оправданий плохой документации.
Действительно, довольно часто триггеры используются не по назначению. На самом деле в большинстве случаев они вам даже не нужны. Но это не обязательно делает их плохими.
Мне приходит в голову сценарий, в котором триггеры полезны, - это когда у вас есть устаревшее приложение, для которого у вас нет исходного кода и нет возможности его изменить.
Я согласен. Проблемы с триггерами - это люди, а не триггеры. Несмотря на то, что это больше, на что нужно взглянуть, что еще нужно учитывать и увеличивает бремя для кодировщиков, которые правильно проверяют вещи, мы не отбрасываем индексы, чтобы упростить нашу жизнь. (Плохие индексы могут быть такими же плохими, как и плохие триггеры)
Важность триггеров (на мой взгляд) в том, что ...
- Любая система всегда должна быть в допустимом состоянии
- Код для обеспечения этого допустимого состояния должен быть централизованным (не написан в каждом SP)
С точки зрения обслуживания, триггер очень полезен для кодировщиков-конкурентов и проблем для более молодых / любительских. Но этим людям нужно как-то учиться и расти.
Думаю, все сводится к вашей рабочей среде. Есть ли у вас надежные люди, которые хорошо учатся и которым можно доверять в методичности? Если нет, у вас, по-видимому, есть два варианта:
.
- Примите тот факт, что вам придется потерять функциональность, чтобы компенсировать
.
- Признайте, что вам нужны другие люди или лучшее обучение и менеджмент.
Они звучат резко, и я думаю, что это так. Но, на мой взгляд, это основная правда ...
>>> Проблемы с триггерами есть у людей. Да, если бы люди могли писать код на ассемблере, работать с дрянным графическим интерфейсом, правильно угадывать, толкать или тянуть плохо спроектированную дверь ... Любая «особенность», которую люди постоянно ошибаются, - это «зло».
@Fakrudeen, любой разработчик, который неправильно использует триггеры, не может получить доступ к базе данных.
В основном да.
Сложность триггера в том, что он работает «за вашей спиной»; разработчик, обслуживающий приложение, может легко не понять, что оно существует, и внести изменения, которые могут испортить ситуацию, даже не заметив.
Это создает уровень сложности, который просто добавляет работы по техническому обслуживанию.
Вместо использования триггера хранимую процедуру / подпрограмму обычно можно заставить делать то же самое, но ясным и поддерживаемым способом - вызов хранимой подпрограммы означает, что разработчик может посмотреть ее исходный код и точно увидеть, что происходит.
Это преимущество триггера, а не недостаток! Нельзя гарантировать, что сохраненные процедуры будут вызываться при каждом изменении данных. Помимо графического интерфейса существует множество способов изменения данных.
HLGEM, это зависит от вашего контроля доступа. Вы можете запретить любое изменение таблиц напрямую, кроме как через хранимую процедуру.
Я думаю, дело в том, что если, например, записи в двух таблицах ВСЕГДА должны создаваться и уничтожаться вместе, независимо от того, как вы обращаетесь к базе данных, и независимо от того, кто вы и какие у вас разрешения, то триггеры - единственное законное решение. . Тот простой факт, что возможный назначает слишком много или неправильных разрешений и ожидает, что люди будут знать, какие хранимые процедуры должны использоваться, означает, что база данных рискует потерять свою целостность. Это точно так же, как отношения внешнего ключа. Это просто НАИЛУЧШИЙ и НАИБОЛЕЕ НАДЕЖНЫЙ обеспечивается ядром базы данных.
Если записи всегда должны создаваться / уничтожаться вместе, создайте проверочное ограничение, которое гарантирует, что это так. Таким образом, тот, кто нарушает правила, получает ошибку, а не скрытое поведение, которое волшебным образом исправляет ситуацию без его ведома или согласия.
Я знаю разработчиков, которые думают, что триггеры всегда должны использоваться там, где это самый прямой способ достижения желаемой функциональности, и разработчиков, которые никогда не будут этого делать. Это почти как догма между двумя лагерями.
Однако я лично полностью согласен с MarkR - вы можете (почти) всегда писать код, функционально эквивалентный триггеру, который будет более наглядным и, следовательно, более простым в обслуживании.
За исключением того, что не вся работа по попаданию в базу данных проходит через код приложения.
Не зло. Они действительно упрощают такие вещи, как
1. регистрация / аудит изменений в записях или даже схемах баз данных
У вас может быть триггер ALTER TABLE, который откатывает изменения в вашей производственной среде. Это должно предотвратить любые случайные изменения таблицы.
2. обеспечение ссылочной целостности (отношения первичный / внешний ключ и т. д.) В нескольких базах данных.
Вы можете откатить операторы DDL?
Как правило, нет. Единственный способ остановить это - удалить это разрешение из учетных записей пользователей.
В некоторых механизмах баз данных вы можете (например, PostgreSQL).
@Andrew - В SQL Server это возможно. SQL Server 2005+ также имеет триггеры DDL, которые срабатывают при таких событиях, как ALTER TABLE.
Триггеры чрезвычайно эффективны и полезны, существует множество сценариев, в которых триггер - лучшее решение проблемы.
Они также являются очень хорошим инструментом для «взлома». Часто возникают ситуации, когда вы не контролируете сразу и код, и базу данных. Если вам нужно подождать 2 месяца до следующего основного выпуска вашего кода, но вы можете сразу применить исправление к своей базе данных, тогда вы можете поместить триггер в таблицу для выполнения некоторых дополнительных функций. Затем, когда выпуск кода станет возможным, вы можете при желании заменить этот триггер своей закодированной версией той же функциональности.
В конце концов, все «зло», если вы не знаете, что это делает. Решить, что триггеры вызваны тем, что есть разработчики, которые их не понимают, - это то же самое, что утверждать, что автомобили - зло, потому что некоторые люди не умеют водить ...
Я думаю, что они могут быть злыми, но только такими же злыми, как и все остальное в разработке.
Хотя на самом деле у меня нет большого опыта работы с ними, они были у меня в недавнем проекте, над которым я работал, и который привел меня к такому выводу. Проблема, с которой я столкнулся с ними, заключается в том, что они могут привести к тому, что бизнес-логика окажется в двух местах: библиотеке кода а также и базе данных.
Я рассматриваю это как аналогичный аргумент с использованием sprocs. Часто у вас будут разработчики, которые действительно хорошо умеют писать бизнес-логику на языке SQL в базе данных, в то время как люди, которые этого не делают, будут иметь свою бизнес-логику где-то еще.
Итак, мое практическое правило - посмотрите, какова структура вашего проекта. Если кажется целесообразным хранить бизнес-логику в базе данных, было бы полезно иметь триггеры.
Нет, они не злые - их просто неправильно понимают :-D
Триггеры имеют правильное применение, но слишком часто в качестве ретро-хака, который в конечном итоге ухудшает ситуацию.
Если вы разрабатываете БД как часть приложения, логика всегда должна быть в коде или в sprocs, выполняющих вызов. Триггеры в дальнейшем просто приведут к проблемам с отладкой.
Если вы понимаете, как блокировка, взаимоблокировка и как БД обращаются к файлам на диске, тогда правильное использование триггеров (например, аудит или архивирование прямого доступа к БД) может быть действительно полезным.
Сказать, что они злые - это преувеличение, но они могут вызвать сетку. Когда срабатывание одного триггера вызывает срабатывание других триггеров, это становится действительно сложным. Допустим, они неприятны: http://www.oracle.com/technology/oramag/oracle/08-sep/o58asktom.html
Реализовать бизнес-логику в Oracle с помощью триггеров сложнее, чем кажется, из-за проблем с множественным параллелизмом. Вы не увидите изменений в другом сеансе, пока другие сеансы не будут зафиксированы.
У триггеров есть свои применения: ведение журнала / аудит и поддержание даты «последнего изменения» - два очень хороших применения, о которых упоминалось в предыдущих ответах.
Однако одним из основных принципов хорошего дизайна является то, что бизнес-правила / бизнес-логика / все, что вы хотите называть, должны быть сосредоточены в одном месте. Размещение части логики в базе данных (через триггеры или хранимые процедуры), а также в приложении нарушает этот принцип. Дублирование логики в обоих местах еще хуже, поскольку они неизбежно рассинхронизируются друг с другом.
Существует также проблема «принципа наименьшего удивления», о котором уже упоминалось.
Правильно, он должен быть в одном месте, в базе данных. Логика, которая влияет на целостность данных, должна ВСЕГДА присутствовать в базе данных и никогда в приложении, где она может или не может быть вызвана при воздействии на данные в базе данных.
@HLGEM: Это зависит от того, может ли база данных иметь доступ к информации, которая позволяет ей определять, действительны ли данные. Это не всегда так; когда валидатор находится в другой организации (например, для данных кредитной карты или банковского счета), то БД не может знать, правильно ли это - при условии, что это не БД банка! - и ему придется полагаться на заявление о принудительном исполнении. Чего вы не хотите, так это того, чтобы база данных производила случайные подключения к сторонним службам, поскольку это плохо, когда дело доходит до развертывания сервера.
@HLGEM: хотя я не готов полностью исключить возможность размещения всей логики приложения в базе данных, я считаю, что лучше всего поместить ее в другое место, как правило, многоразовый объектно-ориентированный слой, который можно использовать для всех приложений, обращающихся к база данных. Пока ваше приложение обращается к базе данных только через объектный уровень, все равно будут применяться те же гарантии всегда вызываемой логики.
Никогда не работал над бизнес-приложением, которое только вставляло данные в базу данных через объектный слой, и я не хотел бы работать с ним. Глупо вводить миллион записей или обновлять все цены через процесс, предназначенный для обработки только одной записи за раз. Слой объектов - совершенно неподходящее место для обеспечения целостности данных, поэтому во многих базах данных возникают проблемы с целостностью.
@HLGEM Именно по этой причине я работаю над расширением нашего ORM, чтобы он работал как триггер, используя набор изменений всего в транзакции. Это кажется немного глупым, но не позволяет нам иметь всю нашу бизнес-логику в приложении, за исключением тех случаев, когда это не так (только несколько таблиц когда-либо нуждаются в массовом обновлении). Это также позволит всем разработчикам писать и использовать их на том языке, который им наиболее удобен и где есть доступ ко всем созданным нами абстракциям объектов.
Многие процессы не могут использовать ORM. Я определенно не могу использовать его в SSIS или SSRS. Будут специальные запросы для исправления неверных данных или проблемных записей, они НИКОГДА не будут проходить через ORM, потому что это разовые исправления, а не исправления приложения. Конечно, большой импорт данных никогда не должен проходить через ORM. Намного лучше иметь настоящие триггеры, чем что-то подделать для ORM, который легко обойти.
Инструменты никогда не бывают злом. Применение этих инструментов может быть вредным.
Я никогда не был более противоречивым после прочтения комментария. С одной стороны, я за вторую поправку и считаю, что оружие не является злом по своей сути: это человек, использующий его. С другой стороны, я считаю, что триггеры ЯВЛЯЮТСЯ злом ... Я думаю, что у меня экзистенциальный кризис ...
Пушки @vbullinger не злые, но их спусковые хуки;)
: D Обобщения опасны (рекурсивно). Были ли у вас «инструменты» пыток, которые инквизиторы использовали, чтобы «вызвать» признание? +1 за перспективу в любом случае.
Триггеры - хороший инструмент при правильном использовании. Особенно для таких вещей, как аудит изменений, заполнение сводных таблиц и т. д.
Теперь они могут быть «злыми», если вы окажетесь в «аду триггеров» с одним триггером, который запускает другие триггеры. Однажды я работал над продуктом COTS, у которого были так называемые «гибкие триггеры». Эти триггеры хранились в таблице, поскольку динамические строки sql были скомпилированы каждый, когда они были выполнены. Скомпилированные триггеры будут искать и видеть, есть ли в этой таблице какие-либо гибкие триггеры для запуска, а затем компилировать и запускать "гибкий" триггер. Теоретически это звучало как действительно крутая идея, потому что продукт легко настраивался, но на самом деле база данных сильно взорвалась из-за всех компиляций, которые ей приходилось делать ...
Так что да, они великолепны, если вы смотрите на то, что делаете, в перспективе. Если это что-то довольно простое, например, аудит, обобщение, автопоследовательность и т. д., Проблем нет. Просто помните о скорости роста таблицы и о том, как триггер повлияет на производительность.
Я считаю, что триггеры не только не зло, но и необходимы для хорошего проектирования баз данных. Программисты считают, что на базы данных влияет только их приложение. Они часто ошибаются. Если целостность данных должна поддерживаться независимо от того, откуда произошло изменение данных, триггеры являются обязательным требованием, и глупо избегать их, потому что некоторые программисты слишком этноцентричны, чтобы полагать, что на что-то может влиять что-то иное, чем их ценное приложение. Если вы компетентный разработчик базы данных, несложно спроектировать, протестировать или устранить неполадки триггера. Также нетрудно определить, что триггер вызывает неожиданный результат, если вам приходит в голову (как это происходит со мной) посмотреть туда. Если я получаю сообщение о том, что таблица, на которую я не ссылаюсь в моем sp, имеет ошибку FK, я знаю, даже не задумываясь об этом, что триггер вызывает проблему, как и любой компетентный разработчик базы данных. Размещение бизнес-правил только в приложении - это причина номер один, которую я обнаружил для плохих данных, поскольку другие даже не подозревают о существовании этого правила и нарушают его в своих процессах. Правила, ориентированные на данные, относятся к базе данных, а триггеры являются ключом к применению более сложных.
Правила, ориентированные на данные, принадлежат базе данных
у меня был some programmers are too ethnocentric to consider that something other than their prized application may be affecting things
Идея триггеров - не зло, ограничение вложенности триггеров - зло.
Они определенно не злые. Я нашел триггеры ценными во время рефакторинга схем базы данных, при переименовании столбца или разделении столбца на два столбца или наоборот (пример: случай имени / фамилии) и помощи при переходе.
Они также очень полезны для одитинга.
Этот ответ относится конкретно к SQL Server. (хотя это также может относиться к другим СУБД, о которых я понятия не имею. Я бы предпочел дать это как ответ здесь, но это было закрыто как обман.)
Одним из аспектов, не упомянутых до сих пор ни в одном из ответов, является безопасность. Поскольку по умолчанию триггеры выполняются в контексте пользователя, который выполняет инструкцию, вызывающую срабатывание триггера, это может вызвать угрозу безопасности, если не будут проверены все триггеры.
Пример, приведенный в BOL под заголовком «Управление безопасностью триггеров», относится к пользователю, который создает триггер, содержащий код GRANT CONTROL SERVER TO JohnDoe ;, для повышения своих собственных разрешений.
На высоком уровне есть два варианта использования триггеров1.
1) Чтобы все происходило "автоматически". В этом случае триггеры вызывают побочный эффект, они изменяют данные способами, которые не ожидались, учитывая (примитивный) оператор вставки, обновления или удаления, который был выполнен и вызвал срабатывание триггера.
По общему мнению, триггеры действительно вредны. Потому что они изменяют хорошо известную семантику операторов INSERT, UPDATE или DELETE. Изменение семантики этих трех примитивных операторов SQL укусит других разработчиков, которым в будущем потребуется работать с таблицами базы данных, которые больше не ведут себя ожидаемым образом при работе с ними с помощью примитивов SQL.
2) Для обеспечения соблюдения правил целостности данных, кроме тех, с которыми мы можем иметь дело декларативно (с помощью CHECK, PRIMARY KEY, UNIQUE KEY и FOREIGN KEY). В этом случае все триггеры делают это данные QUERY (SELECT), чтобы проверить, разрешено ли изменение, которое вносится INSERT / UPDATE / DELETE, или нет. Точно так же, как для нас действуют декларативные ограничения. Только в этом случае мы (разработчики) запрограммировали исполнение.
Использование триггеров для последнего варианта использования не опасно.
Я пишу об этом в блоге: http://harmfultriggers.blogspot.com
При использовании триггеров для ссылочной целостности справиться с проблемами параллелизма сложнее, чем кажется.
Согласовано. Но проще ли использовать другие средства?
Я бы сказал, что номер один вреден, только если у вас есть некомпетентные разработчики.
Хотя есть МНОГО некомпетентных разработчиков, лол.
Я бы не согласился, что триггеры вредны. Если вы точно знаете, что делает триггер, и хорошо его запрограммировали, он всегда должен работать должным образом. Единственная проблема здесь - неточная реализация или использование.
Это вполне законный вопрос, но мне не очень нравится сенсационное название. Я думаю что-то вроде "Какие наиболее важные вопросы следует учитывать при реализации триггеров базы данных?" было бы намного лучше.