Вызовет ли увеличение задержки в сети блокировки таблиц в MS SQL Server?

16

Если я делаю один вызов к базе данных SQL Server по сети с высокой задержкой, произойдут ли блокировки таблицы из-за этой задержки? Скажем, я запрашиваю таблицу A для некоторых записей, и SQL Server должен возвращать эти данные по медленной сети - будет ли блокировка чтения в таблице A, пока сервер отправляет ответ по сети, или SQL Server снимает блокировку перед отправкой ответ?

Кроме того, будет ли ответ варьироваться в зависимости от размера ответа? Если он просто должен вернуть несколько КБ против нескольких сотен МБ, будет ли это иметь значение?

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

Эван М
источник
Если вы не укажете nolockподсказку, всегда будет блокировка . Задержка просто определяет, как долго будет удерживаться блокировка.
Брэндон
3
И даже при том nolock, что вы все равно получите замки
billinkc
@brandon Это задокументировано Microsoft где-нибудь? Мои поиски оказались пустыми.
Эван М
1
@ Брэндон НОЛОК не означает, что вы думаете, что это значит.
Аарон Бертран
3
@Brandon Unless you specify a nolock hint, there will always be a lock.<- это означает, что если вы используете nolock, блокировки может не быть. Я просто разъяснял.
Аарон Бертран

Ответы:

15

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

Это не точно, это зависит от уровня изоляции.

По умолчанию READ COMMITTEDблокировки не удерживаются на время выполнения операторов. READ COMMITTEDне обеспечивает согласованность чтения на уровне выписки, единственная гарантия состоит в том, что вы не можете прочитать непереданные данные. Общая блокировка получается и удерживается для чтения строки, а затем освобождается.

Если у вас нет типов LOB.

Типы больших объектов, потенциально очень большие, не могут быть помещены в буфер. Общая блокировка должна быть получена и удерживаться до завершения инструкции, что по сути дает вам REPEATABLE READповедение в READ COMMITTED.

Если я делаю один вызов к базе данных MSSQL по сети с высокой задержкой, произойдут ли блокировки таблицы из-за этой задержки?

Задержка не вызывает блокировку таблицы, нет. Однако, если блокировка таблицы была получена, задержка увеличит ее.

Процитирую кого-то, кто знает механизм этого лучше меня ( @RemusRusanu ):

Результаты возвращаются клиентской программе по мере выполнения. Когда строки «всплывают» в дереве выполнения, перед главным оператором обычно ставится задача записать эти строки в сетевые буферы и отправить их обратно клиенту. Результат не создается сначала в какое-то промежуточное хранилище (память или диск), а затем отправляется обратно клиенту, вместо этого он отправляется обратно в процессе создания (при выполнении запроса). Отправка результата обратно клиенту, конечно, зависит от протокола управления сетевым потоком. Если клиент активно не потребляет результат (например, путем вызова SqlDataReader.Read ()), то в конечном итоге управление потоком данных должно будет заблокировать отправляющую сторону (выполняемый запрос), и это, в свою очередь, приостановит выполнение запрос.[источник]

Там, где результаты потребляются не так быстро, как SQL Server может их доставить, будь то из-за клиента или сети, мы наблюдаем ASYNC_NETWORK_IOнакопление ожиданий. Повторим, это не повлияет на приобретенные блокировки, а только на продолжительность их удержания.

Марк Стори-Смит
источник
9

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

Моя локальная машина вызывала удаленный сервер SQL и выполняла операции SELECT и INSERT для таблицы в рамках небольшой транзакции. На удаленной машине я подключился к локальному экземпляру SQL и использовал цикл WHILE для многократного перебора таблицы sys.dm_tran_locks в поисках любых блокировок в таблице, из которой я изменял и читал. Я установил NetBalancer на сервер и использовал его для эмуляции задержки в сети при сетевом соединении сервера.

Вот что я нашел:

  • Для операторов, которые не возвращают много данных клиенту, задержка не влияет на блокировку. Я возвращал максимум несколько сотен байтов данных. Транзакция на моей машине имела 250 мс WAITFOR, который удерживал блокировки, и когда я увеличивал задержку сети до 5000 мс, длительность блокировки оставалась близкой к 250 мс.
  • Для операторов, которые возвращают много данных, задержка определенно влияет на блокировку. Я возвращал клиенту десятки тысяч строк, и без задержки продолжительность блокировки была короткой. Когда я увеличил задержку, блокировки продолжались, пока я не получил все данные.

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

Эван М
источник
Интересные результаты. С какой клиентской программой / библиотекой это?
Джеймс Л
Хорошая вещь. Есть ли шанс, что вы сможете потратить на это немного больше времени и посмотреть, сможете ли вы определить размер результата, при котором это происходит?
Марк Стори-Смит
@ MarkStorey-Smith Я не думаю, что смогу получить точное значение, и оно, несомненно, будет зависеть от машины. Начиная с vircom.com/security/improve-sql-nic-performance , похоже, что это настройка на вашем локальном сетевом адаптере , а на моем сервере баз данных было установлено значение 'auto'
Эван М
@James Я только что использовал SSMS на обеих машинах
Evan M
0

Если я делаю один вызов к базе данных MSSQL по сети с высокой задержкой, произойдут ли блокировки таблицы из-за этой задержки?

Когда запрос запускается и завершается SQL Server, он выдает результаты, помещает его в выходной буфер и отправляет его клиенту, который затем извлекает результат из выходного буфера. SQL Server не снимет блокировки, удерживаемые запросом, если от клиента не получено подтверждение. Что может привести к блокировке.

Редактировать: Эван, вы можете обратиться к этой статье поддержки MS

В разделе 3

Блокировка, вызванная SPID, чье соответствующее клиентское приложение не получило все строки результатов для завершения

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

Shanky
источник
Спасибо за ваш ответ Шанки! Вы случайно не знаете, документировано ли это где-нибудь?
Эван М
5
Это не правильно.
Марк Стори-Смит
Кажется, это правильно: приложение не выбирает все строки результатов, блокировки могут быть оставлены для таблиц, блокируя других пользователей. Если вы используете приложение, которое прозрачно передает операторы SQL на сервер, приложение должно извлечь все строки результатов. Если это не так (и если его нельзя настроить для этого), возможно, вам не удастся решить проблему блокировки. Чтобы избежать этой проблемы, вы можете ограничить приложения с плохим поведением отчетами или базой данных для поддержки принятия решений ». Более того, я говорил в общих чертах. Вы можете прочитать здесь support2.microsoft.com/kb/224453
Shanky
4
@Shanky Создать большую таблицу. SELECT *от этого в у READ COMMITTEDв одном соединении SSMS, монитор блокирует от другого. В любое время, сколько замков вы держали в руках?
Марк Стори-Смит