Блокирует ли вставка данных в SQL Server всю таблицу? - PullRequest
48 голосов
/ 13 сентября 2011

Я использую Entity Framework , и я вставляю записи в нашу базу данных, которые включают поле BLOB-объектов.Поле большого двоичного объекта может содержать до 5 МБ данных.

При вставке записи в эту таблицу блокируется ли вся таблица?

Итак, если вы запрашиваете какие-либо данные из таблицы,будет ли он блокироваться, пока вставка не будет завершена (я понимаю, что есть способы обойти это, но я говорю по умолчанию)?

Сколько времени потребуется, чтобы вызвать тупик?Будет ли это время зависеть от того, какая нагрузка на сервер, например, если нагрузка невелика, потребуется ли больше времени, чтобы вызвать взаимоблокировку?

Есть ли способ отслеживать и видеть, что заблокировано в каком-либо конкретном случае?время?

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

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

Ответы [ 4 ]

115 голосов
/ 07 октября 2011

Святая корова, у тебя здесь много вопросов, хе. Вот несколько ответов:

При вставке записи в эту таблицу блокирует ли она всю таблицу?

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

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

Этот становится немного хитрее. Если кто-то пытается выбрать данные со страницы в таблице, которую вы заблокировали, тогда да, вы заблокируете их. Вы можете обойти это с такими вещами, как подсказка NOLOCK в операторе select или с помощью Read Committed Snapshot Isolation. Для начала о том, как работают уровни изоляции, посмотрите Плакат об уровнях изоляции Кендры Литтл .

Сколько времени потребуется, чтобы вызвать тупик? Будет ли это время зависеть от того, какая нагрузка на сервер, например если нагрузка невелика, потребуется ли больше времени, чтобы вызвать взаимоблокировку?

Взаимные блокировки не основаны на времени - они основаны на зависимостях. Скажем, у нас такая ситуация:

  • Запрос A содержит несколько блокировок, и чтобы завершить запрос, ему нужны данные, заблокированные Query B
  • В запросе B также есть несколько блокировок, и для завершения запроса ему нужны вещи, заблокированные запросом A

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

Есть ли способ контролировать и видеть, что заблокировано в конкретный момент времени?

Абсолютно - есть динамические административные представления (DMV), которые вы можете запрашивать, например, sys.dm_tran_locks, но самый простой способ - использовать бесплатную хранимую процедуру sp_WhoIsActive Адама Маханича . Это действительно приятная замена sp_who, которую вы можете назвать так:

sp_WhoIsActive @get_locks = 1

Для каждого запущенного запроса вы получите небольшой XML-код, описывающий все блокировки, которые он удерживает. Также есть столбец Блокировка, чтобы вы могли видеть, кто кого блокирует. Чтобы интерпретировать удерживаемые блокировки, вам нужно проверить Books Online описания типов блокировок .

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

Верьте или нет, один запрос может фактически заблокировать сам себя , и да, запросы могут заблокировать только одну таблицу. Чтобы узнать больше о взаимоблокировках, посмотрите Трудность с тупиками от Иеремии Пешка .

3 голосов
/ 13 сентября 2011

Если у вас есть прямой контроль над SQL, вы можете принудительно заблокировать уровень строки, используя:

INSERT INTO MyTable(Id, BigColumn) WITH (ROWLOCK)
VALUES(...)

Эти два ответа могут быть полезны:

Возможно ли принудительное блокирование на уровне строк в SQL Server?

Блокировка таблицы с помощью выбора в Entity Framework

Чтобы просмотреть текущие удерживаемые блокировки в Management Studio, загляните под сервер, затем в «Монитор управления / активности». В нем есть раздел для блокировок по объектам, поэтому вы сможете увидеть, действительно ли вставки вызывают проблему.

0 голосов
/ 03 октября 2011

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

0 голосов
/ 13 сентября 2011

Лучший ответ, который я могу придумать, это: Это зависит.

Лучший способ проверить это - найти SPID вашего соединения и использовать sp_lock SPID, чтобы проверить, установлен ли режим блокировки X на тип TAB. Вы также можете проверить имя таблицы с помощью SELECT OBJECT_NAME(objid). Мне также нравится использовать приведенный ниже запрос для проверки блокировки.

    SELECT RESOURCE_TYPE,RESOURCE_SUBTYPE,DB_NAME(RESOURCE_DATABASE_ID) AS 'DATABASE',resource_database_id DBID,
    RESOURCE_DESCRIPTION,RESOURCE_ASSOCIATED_ENTITY_ID,REQUEST_MODE,REQUEST_SESSION_ID,
    CASE WHEN RESOURCE_TYPE = 'OBJECT' THEN OBJECT_NAME(RESOURCE_ASSOCIATED_ENTITY_ID,RESOURCE_DATABASE_ID) ELSE '' END OBJETO
    FROM SYS.DM_TRAN_LOCKS (NOLOCK)
    WHERE REQUEST_SESSION_ID = --SPID here

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

Я говорю на общем языке, и у меня нет большого опыта работы с BLOB, поскольку я обычно советую разработчикам избегать их, особенно если они больше 1 МБ.

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