ВЫБРАТЬ ДЛЯ ОБНОВЛЕНИЯ с SQL Server

Этот тип обнаружения коллизий часто называют AABB (Ось Выровненные Ограничительные рамки), это - хорошая начальная точка для поиск Google .

76
задан Bill Paetzke 6 May 2010 в 20:48
поделиться

13 ответов

Recently I had a deadlock problem because Sql Server locks more then necessary (page). You can't really do anything against it. Now we are catching deadlock exceptions... and I wish I had Oracle instead.

Edit: We are using snapshot isolation meanwhile, which solves many, but not all of the problems. Unfortunately, to be able to use snapshot isolation it must be allowed by the database server, which may cause unnecessary problems at customers site. Now we are not only catching deadlock exceptions (which still can occur, of course) but also snapshot concurrency problems to repeat transactions from background processes (which cannot be repeated by the user). But this still performs much better than before.

33
ответ дан 24 November 2019 в 11:22
поделиться

Полный ответ можно найти во внутренностях СУБД. Это зависит от того, как работает механизм запросов (который выполняет план запроса, созданный оптимизатором SQL).

Однако одно возможное объяснение (применимое по крайней мере к некоторым версиям некоторых СУБД - не обязательно к MS SQL Server) заключается в том, что существует нет индекса в столбце идентификатора, поэтому любой процесс, пытающийся обработать запрос с « WHERE id =? » в нем, в конечном итоге выполняет последовательное сканирование таблицы, и это последовательное сканирование попадает в блокировку, которую вы применяется процесс. Вы также можете столкнуться с проблемами, если СУБД по умолчанию применяет блокировку на уровне страниц; блокировка одной строки блокирует всю страницу и все строки на этой странице.

Есть несколько способов развенчать это как источник проблем. Посмотрите на план запроса; изучать индексы;

5
ответ дан 24 November 2019 в 11:22
поделиться

Попробуйте использовать:

SELECT * FROM <tablename> WITH ROWLOCK XLOCK HOLDLOCK

Это должно сделать блокировку монопольной и удерживать ее на время транзакции.

1
ответ дан 24 November 2019 в 11:22
поделиться

Попробуйте (блокировка обновления, блокировка строк)

5
ответ дан 24 November 2019 в 11:22
поделиться

Вы пробовали READPAST?

Я использовал UPDLOCK и READPAST вместе, когда обрабатывал таблицу как очередь.

0
ответ дан 24 November 2019 в 11:22
поделиться

Пересмотрите все свои запросы, возможно, у вас есть какой-то запрос, который выбирает без подсказки ROWLOCK / FOR UPDATE из той же таблицы, что и SELECT FOR UPDATE.


MSSQL часто увеличивает эти блокировки строк до страницы блокировки уровня (даже блокировки уровня таблицы, если у вас нет индекса для поля, которое вы запрашиваете), см. это объяснение . Поскольку вы запрашиваете ОБНОВЛЕНИЕ, я могу предположить, что вам нужна надежность на уровне транзакций (например, финансовая, инвентарная и т. Д.). Так что советы на этом сайте не применимы к вашей проблеме. Это просто понимание того, почему MSSQL увеличивает блокировки .


Если вы уже используете MSSQL 2005 (и выше), они основаны на MVCC, я думаю, у вас не должно возникнуть проблем с блокировкой на уровне строк с помощью ROWLOCK / UPDLOCK подсказка. Но если вы уже используете MSSQL 2005 и выше, Я использую PostgreSQL, он также использует MVCC для ОБНОВЛЕНИЯ, я не сталкивался с такой же проблемой. Эскалация блокировок - это то, что решает MVCC, поэтому я был бы удивлен, если бы MSSQL 2005 все еще увеличивал блокировку таблиц с предложениями WHERE, у которых нет индекса в своих полях. Если это (усиление блокировки) все еще имеет место для MSSQL 2005, попробуйте проверить поля в предложениях WHERE, если они имеют индекс.

Отказ от ответственности: я последний раз использовал MSSQL только версии 2000.

1
ответ дан 24 November 2019 в 11:22
поделиться

According to this article, the solution is to use the WITH(REPEATABLEREAD) hint.

1
ответ дан 24 November 2019 в 11:22
поделиться

You cannot have snapshot isolation and blocking reads at the same time. The purpose of snapshot isolation is to prevent blocking reads.

8
ответ дан 24 November 2019 в 11:22
поделиться

Хорошо, для одного выбора по умолчанию будет использоваться "Read Committed" изоляция транзакции, которая блокирует и, следовательно, останавливает запись в этот набор. Вы можете изменить уровень изоляции транзакции с помощью

Set Transaction Isolation Level { Read Uncommitted | Read Committed | Repeatable Read | Serializable }
Begin Tran
  Select ...
Commit Tran

. Это подробно описано в SQL Server BOL

. Ваша следующая проблема заключается в том, что по умолчанию SQL Server 2K5 будет повышать уровень блокировок, если у вас установлено более ~ 2500 блокировок или используется более 40 % «нормальной» памяти в транзакции блокировки. Эскалация переходит на страницу, затем блокируется таблица

. Вы можете отключить эту эскалацию, установив "

3
ответ дан 24 November 2019 в 11:22
поделиться

возможно, сделав mvcc постоянным, можно решить эту проблему (в отличие от только конкретной партии: SET TRANSACTION ISOLATION LEVEL SNAPSHOT):

ALTER DATABASE yourDbNameHere SET READ_COMMITTED_SNAPSHOT ON;

[РЕДАКТИРОВАТЬ: 14 октября]

После прочтения этого: Лучше параллелизм в Oracle, чем в SQL Server? и это: http://msdn.microsoft.com/en -us / library / ms175095.aspx

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

Я пришел к выводу, что вам нужно установить два флага, чтобы постоянно активировать MVCC mssql в данной базе данных:

ALTER DATABASE yourDbNameHere SET ALLOW_SNAPSHOT_ISOLATION ON;
ALTER DATABASE yourDbNameHere SET READ_COMMITTED_SNAPSHOT ON;
5
ответ дан 24 November 2019 в 11:22
поделиться

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

1
ответ дан 24 November 2019 в 11:22
поделиться

Вопрос - доказано ли, что этот случай является результатом эскалации блокировки (т.е. если вы отследите с помощью профайлера события эскалации блокировки, это определенно то, что происходит, чтобы вызвать блокировку)? Если да, то есть полное объяснение и (довольно экстремальное) обходное решение, включающее флаг трассировки на уровне экземпляра для предотвращения эскалации блокировки. См. http://support.microsoft.com/kb/323630 флаг трассировки 1211

Но это, вероятно, будет иметь непреднамеренные побочные эффекты.

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

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

1
ответ дан 24 November 2019 в 11:22
поделиться

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

Перенос ваш SELECT в транзакции при использовании подсказки блокировки WITH (XLOCK, READPAST) даст желаемые результаты. Просто убедитесь, что эти другие одновременные чтения НЕ используют WITH (NOLOCK). READPAST позволяет другим сеансам выполнять тот же SELECT, но для других строк.

BEGIN TRAN
  SELECT *
  FROM <tablename> WITH (XLOCK,READPAST) 
  WHERE RowId = @SomeId

  -- Do SOMETHING

  UPDATE <tablename>
  SET <column>=@somevalue
  WHERE RowId=@SomeId
COMMIT
2
ответ дан 24 November 2019 в 11:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: