Наличие транзакций во всех запросах - PullRequest
6 голосов
/ 08 июля 2010

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

Ответы [ 8 ]

4 голосов
/ 14 июля 2010

Это совершенно не нужно, поскольку каждый оператор SQL выполняется атомарно, т.е. как будто он уже работал в своей собственной транзакции. Фактически, открытие ненужных транзакций может привести к усилению блокировок, даже к тупикам. Если забыть сопоставить COMMIT с BEGIN, транзакция может оставаться открытой до тех пор, пока соединение с базой данных открыто, и мешает другим транзакциям в том же соединении.

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

3 голосов
/ 13 июля 2010

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

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

Кроме того, это увеличивает риск того, что транзакция останется открытой, удерживая блокировки, если не будет предпринята осторожность (например, при SET XACT_ABORT ON ).

Также имеет незначительное влияние на производительность, как показано в ответе @ 8kb . Это иллюстрирует это другим способом с использованием визуального студийного профилировщика.

Настройка

(Тестирование с пустой таблицей)

CREATE TABLE T (X INT)

Явные

SET NOCOUNT ON

DECLARE @X INT

WHILE ( 1 = 1 )
  BEGIN
      BEGIN TRAN

      SELECT @X = X
      FROM   T

      COMMIT
  END

Explicit

Автоматическая фиксация

SET NOCOUNT ON

DECLARE @X INT

WHILE ( 1 = 1 )
  BEGIN
      SELECT @X = X
      FROM   T
  END 

Auto Commit

Они оба тратят время на CMsqlXactImp::Begin и CMsqlXactImp::Commit, но в случае явных транзакций это тратит значительно большую долю времени выполнения в этих методах и, следовательно, меньше времени на полезную работу.

+--------------------------------+----------+----------+
|                                | Auto     | Explicit |
+--------------------------------+----------+----------+
| CXStmtQuery::ErsqExecuteQuery  | 35.16%   | 25.06%   |
| CXStmtQuery::XretSchemaChanged | 20.71%   | 14.89%   |
| CMsqlXactImp::Begin            | 5.06%    | 13%      |
| CMsqlXactImp::Commit           | 12.41%   | 24.03%   |
+--------------------------------+----------+----------+
2 голосов
/ 18 июля 2010

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

Одним из первых и самых простых способов повышения производительности является удаление всех BEGIN TRAN и COMMIT TRAN для хранимых процедур, которые выполняют только SELECT.

Вот простой тестдля демонстрации:

/* Compare basic SELECT times with and without a transaction */

DECLARE @date DATETIME2
DECLARE @noTran INT
DECLARE @withTran INT

SET @noTran = 0
SET @withTran = 0

DECLARE @t TABLE (ColA INT)
INSERT @t VALUES (1)

DECLARE 
  @count INT,
  @value INT

SET @count = 1

WHILE @count < 1000000
BEGIN

  SET @date = GETDATE()
  SELECT @value = ColA FROM @t WHERE ColA = 1
  SET @noTran = @noTran + DATEDIFF(MICROSECOND, @date, GETDATE())

  SET @date = GETDATE()
  BEGIN TRAN
  SELECT @value = ColA FROM @t WHERE ColA = 1
  COMMIT TRAN
  SET @withTran = @withTran + DATEDIFF(MICROSECOND, @date, GETDATE())

  SET @count = @count + 1
END

SELECT 
  @noTran / 1000000. AS Seconds_NoTransaction, 
  @withTran / 1000000. AS Seconds_WithTransaction

/** Results **/

Seconds_NoTransaction                   Seconds_WithTransaction
--------------------------------------- ---------------------------------------
14.23600000                             18.08300000

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

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

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

2 голосов
/ 17 июля 2010

Один плюс: вы можете добавить еще одну ВСТАВКУ (например), и она уже безопасна.

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

Если каждый вызов является простым CRUD без вложенности, то это бессмысленно: но если вы вкладываете или делаете несколько записей до TXN, то хорошо иметь согласованный шаблон.

2 голосов
/ 14 июля 2010

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

Однако, если код буквально

begin transaction
statement
commit

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

1 голос
/ 16 июля 2010

Синтаксис BEGIN TRANSACTION / COMMIT не должен использоваться в каждой хранимой процедуре по умолчанию, если только вы не пытаетесь охватить следующие сценарии:

  1. Вы включаете параметр WITH MARK, потому что хотитедля поддержки восстановления базы данных из резервной копии в определенный момент времени.

  2. Вы намереваетесь перенести код с SQL Server на другую платформу базы данных, например Oracle.По умолчанию Oracle не фиксирует транзакции.

1 голос
/ 14 июля 2010

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

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

1 голос
/ 14 июля 2010

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

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

...