Хорошая идея использовать NOLOCK для обхода сценария запроса / обновления? - PullRequest
0 голосов
/ 21 марта 2011

Я извлекаю записи из базы данных, публикую их содержимое в очереди MSMQ для транзакций, затем обновляю строку, чтобы указать, что она была опубликована. Enqueing-and-Updating происходит внутри TransactionScope, который сам находится внутри цикла чтения DataReader, который проходит через все записи. То есть: чтение происходит за пределами TransactionScope. Примерно так:

SqlConnection conn = new SqlConnection(ConnectionString);
conn.Open();

SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "GetUnpublishedEvents";
cmd.CommandType = System.Data.CommandType.StoredProcedure;

SqlDataReader reader = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection
                                       | System.Data.CommandBehavior.SingleResult);

while (reader.Read())
   using (TransactionScope scope = new TransactionScope())
   {
      string ID = reader.GetString(0);
      string data = reader.GetString(1);

      SqlConnection updateConn = new SqlConnection(ConnectionString);
      updateConn.Open();
      SqlCommand updateCommand = updateConn.CreateCommand();
      updateCommand.CommandText = "SetEventAsPublished";
      updateCommand.CommandType = System.Data.CommandType.StoredProcedure;
      updateCommand.Parameters.Add(new SqlParameter("@ID", ID));

      updateCommand.ExecuteNonQuery();
      updateConn.Close();

      Message msg = new Message(data);
      RaiseMessageArrived(msg);
      scope.Complete();
   }

   reader.Close();

Хранимая процедура SetEventAsPublished использовалась с ошибкой Timeout, пока я не изменил GetUnpublishedEvents для использования NOLOCK. Мой вопрос: это хорошая идея? Было ли исключение тайм-аута намеком на то, что я должен делать это другим способом?

Я знаю, что NOLOCK эквивалентен в SQL Server READUNCOMMITTED. Однако я не слишком беспокоюсь о том, чтобы читать непринятые данные в этом приложении (в первую очередь они не вставляются в транзакцию).

Edit:

Хранимые процедуры тривиальны. GetUnpublishedEvents это просто:

SELECT id, data
FROM eventsTable WITH (NOLOCK)
WHERE data IS NOT NULL
AND published IS NULL;

Пока SetEventAsPublished это:

UPDATE eventsTable
SET published = GETDATE()
WHERE ID = @ID;

1 Ответ

1 голос
/ 21 марта 2011

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

В основном вывы делаете SQL-эквивалент ReaderWriterLock.Он оптимизирован для чтения, но может быть повышен, чтобы разрешить запись в той же области.

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

...