2016-12-03 2 views
0

Предположим, у нас есть таблица Users с тремя столбцами.SQL Server: блокировки и эксклюзивный тип выбора

UserId - primary key clustered int 
Username - nvarchar(50) 
CityId - int, which has a non-unique non-clustered index (mouthful). 

Если я избранная и с эксклюзивным замком и начать тран на одной вкладке:

declare @CityId int = 10 

begin tran 
    SELECT * 
    FROM [dbo].Users WITH (XLOCK,INDEX (MyCityIndex)) 
    WHERE CityId = @CityId 

И заметьте, я не совершает или откат транзакции.

Тогда в другом (YES ДРУГОЙ TAB ELSE SQL СДЕЛАЕТ НЕКОТОРУЮ ОПТИМИЗАЦИЯ И не будут работать) вкладку, я бегу:

declare @CityId int = 10 

begin tran 
    SELECT * 
    FROM [dbo].Users WITH (XLOCK, INDEX (MyCityIndex)) 
    WHERE CityId = @CityId 

Это, очевидно, будет блокировать, если я использую тот же CityId (10). Но я думаю, что произойдет, если я использую CityId = 11?

declare @CityId int = 11 

Будет работать.

Но он будет работать, если я сделаю поиск подсказок индекса, иначе он не сработает, и даже если я поставлю CityId = 11, тогда он будет блокировать и ждать другого транса, который не удастся.

Что здесь происходит?

Когда он считывает данные с использованием исключительной блокировки, выполняет полное сканирование таблицы, а затем, когда он попадает в запись, в которую он заблокирован, заблокирован? В самом деле?

Что произойдет, если индексы будут фрагментированы и попадут в строку, которая фактически заблокирована, которая не содержит ее идентификатора. Будет ли это блокироваться?

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

http://sqlblog.com/blogs/louis_davidson/archive/2006/12/13/does-xlock-always-prevent-reads-by-others.aspx

Я использую 2014

ответ

0

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

Я думаю, вы можете избежать намека, если вы явно указали INCLUDE другие 2 столбца в определении MyCityIndex. Кроме того, добавьте остальные 3 столбца в список ключей MyCityIndex после CityId.

Приведенный ниже пример использует MyCityIndex и не блокирует даже без подсказки, поскольку он касается только запрошенных значений CityId. Если вы удалите предложение INCLUDE, выполняется кластерное сканирование индекса, и второй запрос будет заблокирован.

CREATE TABLE dbo.Users(
     CityId int 
    , UserID int 
     CONSTRAINT PK_Users PRIMARY KEY CLUSTERED 
    , OtherData int 
    ); 
CREATE INDEX MyCityIndex ON dbo.Users(CityId) INCLUDE(UserID, OtherData); 
GO 

INSERT INTO dbo.Users VALUES(1,1,1); 
INSERT INTO dbo.Users VALUES(1,2,1); 
INSERT INTO dbo.Users VALUES(1,3,1); 
INSERT INTO dbo.Users VALUES(10,4,1); 
INSERT INTO dbo.Users VALUES(10,5,1); 
INSERT INTO dbo.Users VALUES(10,6,1); 
INSERT INTO dbo.Users VALUES(11,7,1); 
INSERT INTO dbo.Users VALUES(11,8,1); 
INSERT INTO dbo.Users VALUES(11,9,1); 
UPDATE STATISTICS dbo.Users; 
GO 

--run this on session 1 
DECLARE @CityId int = 10; 
BEGIN TRAN 
     --SELECT * FROM dbo.Users with (XLOCK,INDEX (MyCityIndex)) where CityId= @CityId 
    SELECT * FROM dbo.Users with (XLOCK) WHERE CityId= @CityId; 
--ROLLBACK; 
GO 

--run this on session 2 
DECLARE @CityId int = 11; 
BEGIN TRAN 
     --SELECT * FROM dbo.Users with (XLOCK,INDEX (MyCityIndex)) where CityId= @CityId 
    SELECT * FROM dbo.Users with (XLOCK) WHERE CityId= @CityId; 
--ROLLBACK; 
GO 
+0

ty для ответа, но вы все еще не ответили на мой вопрос. На самом деле нажимает запись блокировки при выполнении инструкции «select ... where ..», block? Что делать, если индекс фрагментирован и содержит данные, которых не должно быть. Будет ли мое решение по-прежнему работать? – Aflred

+0

@Aflred, я добавил сценарий к моему ответу, который показывает, что запрос не будет заблокирован поиском даже без подсказки индекса. Фрагментация не приводит к тому, что индексные страницы содержат данные, которые не должны; это может уменьшить ожидаемую продолжительность жизни страницы и вызвать больше ввода-вывода. –

+0

Точное поведение, которое я получаю, и это правильно, и вы сами пытаетесь это сделать. Да, вы ответили на весь мой вопрос: «Фрагментация не приводит к тому, что индексные страницы содержат данные, которые не должны; это может уменьшить ожидаемую продолжительность жизни страницы и вызвать больше IO ', поэтому thats that.I было неправильно в отношении индексов.' Я предполагаю, что все зависит от плана оптимизации sql. – Aflred

Смежные вопросы