Действительно ли мне нужны триггеры для реляционной базы данных, например, PostgreSQL?

10

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

Например, мы храним клиентов и хотим выполнить некоторую проверку, которую нелегко выполнить на уровне DDL. https://severalnines.com/blog/postgresql-triggers-and-stored-function-basics

Другой пример - аудит.

Обновить

Как триггеры и транзакции базы данных работают вместе. Например, если я хочу выполнить проверку вставляемых данных. Это делается внутри транзакции. Что происходит раньше: транзакция зафиксирована или триггер выполнен?

Ян Хонски
источник
However, why not perform validation of data on the application side before storing them into the database?ну, эти два не являются взаимоисключающими. Скорее всего, вы будете проверять разные вещи с обеих сторон. В то время как валидации на стороне приложения ориентированы на бизнес, валидации в базе данных более ориентированы на данные. Думайте в базе данных, питаемой несколькими различными приложениями.
Laiv
Вам нужно будет вставить данные из внешнего источника, который просто делает бессмысленный сброс данных в вашу систему? Если это так, у вас могут быть случаи, когда вам понадобятся данные, введенные в недопустимом формате для последующего исправления. В этом случае триггеры будут вызывать бесконечные проблемы. Просто имейте это в виду. Иногда вам не нужен триггер.
Грег Бургхардт
Ваше обновление должно быть вопросом само по себе, может быть, на SO, но на ваш вопрос уже есть ответ на Database Administrators.SE . Короче говоря, даже триггер «после обновления» выполняется до того, как транзакция будет зафиксирована, и если в триггере будет сгенерировано исключение, это вызовет откат.
Док Браун
@GregBurghardt В большинстве баз данных есть операторы, которые можно использовать для отключения триггеров для таких видов деятельности.
Blrfl
1
@Blrfl: Да, но вы должны знать, что эти триггеры могут быть временно отключены для всех подключенных пользователей, когда вы хотите только условно отключить эти проверки для текущего сеанса.
Грег Бургхардт

Ответы:

12

Это зависит от того, какую систему приложений вы строите:

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

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

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

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

Смотрите также этот старый пост SE: Application Logic Vs DB Trigger для очистки базы данных.

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

Док Браун
источник
3

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

Ответ зависит от того, как вы видите систему.

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

И наоборот, базу данных можно рассматривать как сложную форму файла, которая находится под прямым и полным контролем приложения. В этом смысле база данных превращается в чистый инструмент сериализации и навигации по документам. Он может предоставлять некоторые расширенные возможности для поддержки запросов и обслуживания документов (как это делают JSON или XML-инструменты), но, опять же, в этом нет необходимости (как это делают большинство файловых потоков). В этом случае ответственность за поддержание правильного формата и содержимого в файле лежит исключительно на программах. В этом представлении есть одно приложение.

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

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

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

Независимо от того, какое представление вы принимаете, оно всегда платит за проверку данных на границах.

  • Проверьте поля в пользовательском интерфейсе, который вводит пользователь
  • Проверьте запрос сети / API, прежде чем он покинет клиента
  • Проверяйте запрос сети / API на сервере, прежде чем делать что-либо
  • Проверка данных, передаваемых в бизнес-правила
  • Проверяйте данные перед сохранением
  • Проверка данных после извлечения из постоянства
  • ну и так далее

То, насколько валидация оправдана на каждой границе, зависит от того, насколько рискованно ее не валидировать.

  • умножить два числа вместе?
    • Вы ошиблись номером, это проблема?
  • Вызов процедуры в данной области памяти?
    • Что находится в этом месте памяти?
    • Что происходит, если объект не существует или находится в плохом состоянии?
  • используя регулярное выражение для строки, содержащей кандзи?
    • Может ли модуль regex обрабатывать юникод?
    • Может ли регулярное выражение обрабатывать Unicode?
Kain0_0
источник
Централизация логики валидации хороша, но триггеры imho не являются хорошим способом реализовать это. Раньше я работал в системе, где все приложения совместно использовали базу данных, и вся логика валидации и побочные эффекты реализовывались в базе данных с помощью триггеров и хранимых процедур. У меня сложилось впечатление, что лучше иметь микросервис перед базой данных и реализовывать всю логику там. Нетривиальная логика в базе данных SQL является анти-паттерном.
Джори Себрехтс
1
@JoeriSebrechts Хорошо, я укушу: почему нетривиальная логика в базе данных является антипаттерном, и что делает ее скорее антипаттерном, чем помещением ее в отдельно поддерживаемую программу?
Blrfl
@Blrfl Две причины: API для доступа к логике в БД уступает API веб-службы (сложнее для версии, сложнее в использовании, нелегко кешировать, ...), а базы данных затрудняют чистую структуру и поддержку Кодовая база размещена внутри них. По моему опыту, проще размещать логику в веб-сервисе перед базой данных, чем внутри этой базы данных.
Джори Себрехтс
@JoeriSebrechts Я согласен, что большинство платформ баз данных предоставляют ужасные инструменты для реализации надежного, полезного и развивающегося API. Во многих отношениях это, безусловно, приглашение чувствовать большую боль. Моя точка зрения заключалась в том, что речь идет о перспективе, понимание того, что БД представляет собой необычный файл или что это действительно отдельная служба, приводит к следующему вопросу, который заключается в том, как обернуть его для поддержки этого стиля использования. Я уточню свой ответ, чтобы прояснить это.
Kain0_0
2

Нет, вы никогда не должны использовать триггеры для проверки.

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

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

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

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

Валидация является задачей приложения. Тот факт, что почтовый индекс Германии состоит только из цифр, является проверкой приложения, а не базы данных. Линия тонкая, поэтому вам может понадобиться подумать / обсудить в некоторых случаях, что-то должно быть в триггере (защита целостности вашей базы данных) или в приложении (пользователь сталкивается с проверкой).

Менно Хёльшер
источник
Я просто хотел добавить, что если операционному агенту нужно добавить комплексное правило проверки, которое должно быть в базе данных, он всегда может использовать хранимые процедуры в качестве более безопасной альтернативы.
Борхаб
@ Боржаб: Проверка правильности базы данных, может быть. Но пользователь сталкивается с проверкой? Нет.
Менно Хёльшер
1
Ваше первое утверждение гласит: «никогда не используйте триггеры для проверки» , но ниже вы пишете: «Да, вы можете использовать триггеры для определенных видов проверки, и по сути не ясно, где провести черту». Это звучит довольно противоречиво. Я бы порекомендовал удалить ваше первое предложение, которое значительно улучшило бы ваш ответ. Да, и ваше последнее предложение не отвечает на вопрос об обновлении OP, так как «до / после» не имеет ничего общего с транзакцией. Я бы порекомендовал также удалить его. (см. мой комментарий ниже вопроса ОП).
Док Браун
@DocBrown Различие заключается в защите базы данных от повреждения и проверке пользователя. Таким образом, в «любой дальнейшей проверке» я имею в виду проверку пользователя. Как я мог сделать это различие более ясным? Для начала я убрал «дальше».
Менно Хёльшер
2
Это прекрасно для проверки в базе данных. Так же, как это можно сделать в приложении. Оба имеют свои преимущества. Выполнение проверки в приложении означает, что вы должны быть очень осторожны каждый раз, когда запускаете SQL без ORM, который необходим практически для каждого сложного приложения.
Qwertie
1

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

Проверка может быть выполнена на уровне переднего плана, но я видел странные ошибки в базе данных, которые я обработал (люди, которые родились в 3000 и т. Д.), И, поскольку некоторые из них я сделал сам, я настоятельно рекомендую иметь дополнительный слой проверки в базе данных, на всякий случай. Конечно, этих типов ошибок можно избежать с помощью проверочных ограничений, и во многих случаях они более эффективны (в MS SQL они являются предпочтительным методом; всегда проверяйте документацию).

Хила Д.Г.
источник
1

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

  1. Для аудита, как описано в других ответах.
  2. Аудит в более широком смысле: если запись в базе данных изменена, триггер может записать событие для асихронной постобработки, например, ночной экспорт в другое приложение.
  3. Триггеры для представлений: триггеры могут быть определены instead of. С помощью этого средства можно вставлять, обновлять и удалять записи из представления. Триггеры могут распространять эти действия на несколько таблиц. Это способ сделать доступным ограниченное представление, не раскрывая детали базовых таблиц.
  4. Чтобы явно сохранить развороты базы данных: предположим, что между таблицами A и B и промежуточной таблицей R существуют отношения N: M. Вы можете определить ограничения внешнего ключа от R до A, а также B, указав, что запись в R должна быть отброшена, если ее соответствующая запись в B удалена. Однако бизнес-логика иногда требует, чтобы записи в A имели как минимум одно отношение к записи в B. В этом случае триггер на удаление R может помочь применить эту логику: если для записи в A последняя запись в R удаляется, тогда триггер может удалить A. В представлении, ориентированном на приложение, необходимо как минимум два оборота. Это пример для проверки. Возможны и другие примеры: кроме случаев использования (1), (2),
  5. Доверие: иногда администраторы базы данных изменяют записи в командной строке, не используя ваше приложение. Админы работают осторожно и знают, что делают. Однако иногда они могут ошибаться. Если последовательность важна, триггер - их ремень безопасности.

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

Клод
источник