Публикация выполнения хранимой процедуры в транзакционной репликации

Если у вас есть одна или несколько хранимых процедур, которые выполняются на издателе и влияют на опубликованные таблицы, рассмотрите возможность включения этих хранимых процедур в публикацию в качестве статей о выполнении хранимой процедуры. Определение процедуры (инструкции CREATE PROCEDURE) копируется Подписчику при инициализации подписки; когда процедура выполняется у Издателя, репликация выполняет соответствующую процедуру у Подписчика. Это может значительно повысить производительность в случаях, когда выполняются большие пакетные операции, так как выполняется только выполнение процедуры, обходя необходимость репликации отдельных изменений для каждой строки. Например, предположим, что в базе данных публикации создается следующая хранимая процедура:

CREATE PROC give_raise AS  
UPDATE EMPLOYEES SET salary = salary * 1.10  

Эта процедура дает каждому из 10 000 сотрудников вашей компании увеличение заработной платы на 10 процентов. При выполнении этой хранимой процедуры на издателе она обновляет зарплату для каждого сотрудника. Без репликации выполнения хранимой процедуры обновление будет отправлено подписчикам в виде большой многоэтапной транзакции:

BEGIN TRAN  
UPDATE EMPLOYEES SET salary = salary * 1.10 WHERE PK = 'emp 1'  
UPDATE EMPLOYEES SET salary = salary * 1.10 WHERE PK = 'emp 2'  

Это повторяется на протяжении 10 000 обновлений.

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

EXEC give_raise  

Это важно

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

Публикация выполнения хранимой процедуры

Изменение процедуры для подписчика

По умолчанию определение хранимой процедуры на издателе распространяется на каждого подписчика. Однако можно также изменить хранимую процедуру на подписчике. Это полезно, если вы хотите выполнить другую логику в компоненте "Издатель" и "Подписчик". Например, рассмотрим sp_big_delete хранимую процедуру на издателе с двумя функциями: она удаляет 1000 000 строк из реплицированной таблицы big_table1 и обновляет нереплицированную таблицу big_table2. Чтобы уменьшить спрос на сетевые ресурсы, следует выполнить удаление миллиона строк в виде хранимой процедуры, опубликовав sp_big_delete. На подписчике можно изменить sp_big_delete, чтобы удалить только 1 миллион строк и не выполнить последующее обновление в big_table2.

Замечание

По умолчанию, все изменения, внесённые с помощью ALTER PROCEDURE у Издателя, передаются Подписчику. Чтобы предотвратить это, отключите распространение изменений схемы перед выполнением ALTER PROCEDURE. Сведения об изменениях схемы см. в разделе "Внесение изменений схемы" в базах данных публикации.

Типы статей о выполнении хранимых процедур

Существует два разных способа публикации выполнения хранимой процедуры: статьи о выполнении сериализуемой процедуры и статье о выполнении процедуры.

  • Параметр сериализации рекомендуется, так как он реплицирует выполнение процедуры, только если процедура выполняется в контексте сериализуемой транзакции. Если хранимая процедура выполняется вне сериализуемой транзакции, изменения данных в опубликованных таблицах реплицируются в виде ряда инструкций DML. Это поведение способствует тому, чтобы данные на подписчике были согласованы с данными на издателе. Это особенно полезно для пакетных операций, таких как большие операции очистки.

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

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

BEGIN TRANSACTION T1  
SELECT @var = max(col1) FROM tableA  
UPDATE tableA SET col2 = <value>   
   WHERE col1 = @var   
  
BEGIN TRANSACTION T2  
INSERT tableA VALUES <values>  
COMMIT TRANSACTION T2  

В предыдущем примере предполагается, что оператор SELECT в транзакции T1 выполняется перед INSERT в транзакции T2.

Если процедура не выполняется в сериализуемой транзакции (с уровнем изоляции, установленным для SERIALIZABLE), транзакция T2 будет разрешена вставлять новую строку в диапазон инструкции SELECT в T1, и она зафиксируется до T1. Это также означает, что оно будет применяться у подписчика до T1. Когда T1 применяется на подписчике, SELECT потенциально может вернуть иное значение, чем у издателя, и это может привести к результату, отличному от UPDATE.

Если процедура выполняется в сериализуемой транзакции, транзакции T2 не будет разрешено вставлять в диапазон, охватываемый инструкцией SELECT в рамках T2. Он будет заблокирован до тех пор, пока T1 не зафиксирует те же результаты у подписчика.

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

Параметр XACT_ABORT

При репликации выполнения хранимой процедуры параметр сеанса, выполняющего хранимую процедуру, должен указывать XACT_ABORT ON. Если для XACT_ABORT задано значение OFF и при выполнении процедуры у Издателя возникает ошибка, то та же ошибка возникнет у Подписчика, что приведет к сбою агента распространения. Указание XACT_ABORT ON гарантирует, что все ошибки, возникшие во время выполнения в Publisher, вызывают откат всего выполнения, избегая сбоя агент распространения. Дополнительные сведения о настройке XACT_ABORTсм. в разделе SET XACT_ABORT (Transact-SQL).

Если требуется параметр XACT_ABORT OFF, укажите параметр -SkipErrors для агент распространения. Это позволяет агенту продолжать применять изменения на подписчике, даже если возникла ошибка.

См. также

Настройки статьи для транзакционной репликации