Вопрос о состоянии состязания SQL Server

Я всегда сохраняю vector.size () в локальной переменной (только если vector.size () не изменяется в цикле for!).
Зачем? Потому что вызывать его на каждой итерации вместо сохранения в локальной переменной намного быстрее. Вот что я испытал в своих приложениях.
Я не могу дать вам реальные цифры, но это заметно изменило.

И всем тем людям, которые жалуются на микрооптимизацию:
Когда вы пишете огромный цикл for, вы просто (просто для удовольствия) вставляете в него ненужное вычитание? Нет.

Почему бы тебе просто не профилировать это? Огромный вектор и std :: time отлично подойдут.

7
задан Hythloth 5 November 2009 в 22:10
поделиться

6 ответов

Установите уровень изоляции транзакции в Serializable.
На более низких уровнях изоляции другие транзакции могут читать данные в строке, которая читается (но еще не изменена) в этой транзакции. Таким образом, две транзакции действительно могут считывать одно и то же значение. При очень низкой изоляции (Read Uncommitted) другие транзакции могут даже читать данные после их изменения (но до фиксации) ...

Подробную информацию об уровнях изоляции SQL Server можно найти здесь

Итак, суть в том, что изоляция level - это критический элемент, позволяющий контролировать, какой уровень доступа к нему получают другие транзакции.

ПРИМЕЧАНИЕ. Из ссылки , около Serializable
Утверждения не могут читать данные, которые были изменены, но еще не зафиксированы другими транзакциями .
Это связано с тем, что блокировки устанавливаются при изменении строки, а не при возникновении Begin Trans . Таким образом, то, что вы сделали, может позволить другой транзакции прочитать старое значение до того момента, когда вы его измените. Поэтому я бы изменил логику, чтобы изменить его в том же операторе, в котором вы его читаете, тем самым одновременно заблокировав его.

begin tran
declare @x int
update def set @x= nextcode, nextcode += 1
waitfor delay '00:00:15'
select @x
commit tran
6
ответ дан 6 December 2019 в 10:01
поделиться

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

В качестве альтернативы вы можете удалить блокировка специально для таблицы DEF путем добавления синтаксиса WITH HOLDLOCK после имени таблицы, например,

SELECT nextcode FROM DEF WITH HOLDLOCK

Здесь нет большой разницы, поскольку ваша транзакция мала, но может быть полезна для снимать блокировки для некоторых SELECT, но не для других в транзакции. Это вопрос «повторяемости против параллелизма».

Пара соответствующих документов MS-SQL.

5
ответ дан 6 December 2019 в 10:01
поделиться

Это не настоящая гонка. Это более распространенная проблема с одновременными транзакциями. Одно из решений - установить блокировку чтения для таблицы и для этого выполнить сериализацию.

1
ответ дан 6 December 2019 в 10:01
поделиться

Резюме:

  • Вы начали транзакцию. На самом деле это ничего не "делает" само по себе, это изменяет последующее поведение
  • Вы читаете данные из таблицы. Уровень изоляции по умолчанию - Read Committed, поэтому этот оператор select не включен в транзакцию.
  • Затем вы ждете 15 секунд
  • Затем вы запускаете обновление. С объявленной транзакцией это будет генерировать блокировку до тех пор, пока транзакция не будет зафиксирована.
  • Затем вы фиксируете транзакцию, снимая блокировку.

Итак, предполагаем, что вы выполнили это одновременно в двух окнах (A и B):

  • A прочитал «следующее» значение из таблицы def, затем перешел в режим ожидания
  • B прочитал то же самое «следующее» значение из таблицы, затем перешел в режим ожидания. (Поскольку A выполнял только чтение, транзакция ничего не блокировала.
3
ответ дан 6 December 2019 в 10:01
поделиться

Вы можете установить для столбца постоянное вычисленное значение. Это позаботится о состоянии гонки.

Сохраненные вычисляемые столбцы

ПРИМЕЧАНИЕ

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

Реализация

Присвойте столбцу следующие свойства в соответствии со спецификацией вычисляемого столбца.

Formula = dbo. GetNextCode ()

Is Persisted = Yes

Create Function dbo.GetNextCode()
Returns VarChar(10)
As
Begin

    Declare @Return VarChar(10);
    Declare @MaxId Int

    Select @MaxId = Max(Id)
    From Table

    Select @Return = Code
    From Table
    Where Id = @MaxId;

    /* Generate New Code ... */

    Return @Return;

End
0
ответ дан 6 December 2019 в 10:01
поделиться

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

Хорошим примером этого являются последовательности postgres, которые вы можете проверить здесь:

Последовательности Postgres

Mysql использует так называемое автоматическое приращение.

Автоматическое приращение MySQL

0
ответ дан 6 December 2019 в 10:01
поделиться
Другие вопросы по тегам:

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