Создание и управление индексами. Создание и управление встроенными процедурами. Оптимизация производительности запросов. Управление транзакциями и блокировками, страница 25

sp_configure ‘nested triggers’, 0

Вы можете захотеть отключить вложенность триггеров потому что:

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

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

Рекурсивные триггеры

Любой триггер может содержать операторы UPDATE, INSERT или DELETE, которые воздействуют на другие таблицы или ту же самую таблицу. Если включена опция рекурсивного вызова, триггер, который изменяет данные в таблице, может активировать себя снова. По умолчанию эта опция отключена, когда база данных создаётся. Вы можете включить эту опцию с помощью оператора ALTER DATABASE.

Следующий оператор включает рекурсивные триггеры:

ALTER DATABASE ClassNorthwind SET RECURSIVE_TRIGGERS ON

sp_dboption имябазыданных, ‘recursive triggers’, TRUE

Если опция вложения отключена, то и рекурсия тоже отключена.

11.4 Примеры триггеров

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

Обеспечение целостности данных

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

Пример

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

USE Northwind

GO

CREATE TRIGGER BackOrderList_Delete

ON Products FOR UPDATE

AS

IF (SELECT BO.ProductID FROM BackOrders AS BO JOIN

Inserted AS I ON BO.ProductID=I.ProductID)>0

BEGIN

DELETE BO FROM BackOrders AS BO

INNER JOIN Inserted AS I

ON BO.ProductID=I.ProductID

END

Обеспечение бизнес ролей

Вы можете использовать триггеры для обеспечения бизнес правил, которые более сложны, чем ограничение CHECK.

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

Пример

Следующий пример показывает, как триггер определяет, какие продукты имеют историю закупок. Если она существует, то происходит откат удаления и триггер возвращает сообщение об ошибке:

USE Northwind

GO

CREATE TRIGGER Product_Delete

ON Products FOR DELETE

AS

IF (SELECT COUNT (*)

FROM [Order Details] INNER JOIN deleted

ON [Order Details].ProductID=Deleted.ProductID

)>0

BEGIN

RAISERROR('Транзакция не может быть принята, этот продукт имеет историю', 16,1)

ROLLBACK TRANSACTION

END

Размышления о производительности

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

*  Триггеры выполняются быстро, потому что таблицы Insert и Deleted расположены в КЭШе.

*  Количество ссылочных таблиц и количество строк влияют на время выполнения.

*  Действия, содержащиеся в триггере, являются частью транзакции.

11.5 Рекомендуемая практика

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

*  Делайте объявление операторов триггеров простыми, на сколько это возможно. Так как триггер является частью транзакции, блокировки сохраняются, пока транзакция не завершится;

*  Включайте проверку рекурсии в рекурсивных триггерах;

*  Минимизируйте использование операторов ROLLBACK в триггерах.

11.6 Лабораторные

Создание триггера

Рассмотрите следующее создание триггера:

USE ClassNorthwind

IF EXISTS ( SELECT name FROM sysobjects

WHERE type = 'TR' AND name = 'OrdDet_Insert' )

DROP TRIGGER OrdDet_Insert

GO

CREATE TRIGGER OrdDet_Insert

ON [Order Details]

FOR INSERT

AS

UPDATE P SET

UnitsInStock = (P.UnitsInStock - I.Quantity)

FROM Products AS P INNER JOIN Inserted AS I

ON P.ProductID = I.ProductID

GO

/* Display results. */