Там нет строки, но (XLOCK, ROWLOCK) заблокирован? - PullRequest
3 голосов
/ 09 августа 2011

Рассмотрим эту простую таблицу: enter image description here

оператор создания таблицы:

CREATE TABLE [dbo].[Test_Serializable](
[Id] [int] NOT NULL,
[Name] [nvarchar](50) NOT NULL
)

, поэтому нет никакого первичного ключа или индекса.

считают его пустыми не имеет никакой строки. Я хочу вставить эту строку (1,'nima'), но я хочу проверить, есть ли строка с Id=1 или нет. Если да, вызовите RAISERROR и, если нет, введите строку. Я пишу этот сценарий:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRY
BEGIN TRAN ins

    IF EXISTS(SELECT * FROM Test_Serializable ts WITH(xlock,ROWLOCK) WHERE ts.Id=1)
        RAISERROR(N'Row Exists',16,1);


    INSERT INTO Test_Serializable
    (
        Id,
        [Name]
    )
    VALUES
    (
        1,
        'nima'
    )
   COMMIT TRAN ins
     END TRY
     BEGIN CATCH
        DECLARE @a  NVARCHAR(1000);
        SET @a=ERROR_MESSAGE();
        ROLLBACK TRAN ins
        RAISERROR(@a,16,1);
     END CATCH

этот скрипт работает нормально, но есть интересный момент.

Я запускаю этот скрипт из 2-х SSMS и шаг за шагом запускаю эти 2 скрипта (в режиме отладки). Однако мой интересный моментТаблица не имеет строки, но один из сценариев, когда оператор IF EXIST блокирует таблицу.

Мой вопрос заключается в том, блокирует ли (XLOCK,ROWLOCK) всю таблицу из-за отсутствия строки? Или блокирует фантомную строку :) !!???

Редактировать 1)

Это мой сценарий:

У меня есть таблица, например, с 6 полями

enter image description here

это правила уникальности:

1) уникальность City_Code + F1_Code

2) уникальность City_Code + F2_Code

3) City_Code + F3_Code + F4_Code имеют uinque

проблема в том, что пользователь может захотеть заполнить city_code и F1_Code, и когда он захочет вставить его в другие поля, мы должны иметь Empty Stringили 0 (для числовых полей) значение.

Если пользователь хочет заполнить City_Code + F3_Code + F4_Code, тогда F1_Code и F2_Code должны иметь Empty String значения

Как я могу проверить это лучше?Я не могу создать уникальный индекс для каждого правила

Ответы [ 2 ]

5 голосов
/ 09 августа 2011

Чтобы ответить на ваш вопрос, уровень изоляции SERIALIZABLE выполняет блокировки диапазона, которые будут включать несуществующие строки в пределах диапазона.

http://msdn.microsoft.com/en-us/library/ms191272.aspx

Блокировка диапазона клавиш обеспечивает выполнение следующих операций сериализуемый:

запрос сканирования диапазона

Синглтон-выборка несуществующей строки

Операция удаления

Операция вставки

4 голосов
/ 09 августа 2011

XLOCK является эксклюзивной блокировкой: так как WHERE пересекает строки, строки блокируются.

SET SERACIZABLE УРОВНЯ ИЗОЛЯЦИИ СДЕЛКИ не касается дубликатов или блокировки строк, она просто исключает возможность «чтения фантома» .С точки зрения блокировки, он принимает блокировки диапазона (например, все строки между A и B)

Таким образом, с помощью XLOCK и SERIALIZABLE вы блокируете таблицу.Вы хотите UPDLOCK, который не является эксклюзивным.

С UPDLOCK этот шаблон не является безопасным.При высокой нагрузке вы по-прежнему будете получать дублирующиеся ошибки, потому что 2 одновременных EXISTS не найдут строку, обе пытаются вставить, одна получает дублирующую ошибку.

Так что просто попытайтесь вставить и перехватить ошибку:

BEGIN TRAN ins
    INSERT INTO Test_Serializable
    (
        Id,
        [Name]
    )
    VALUES
    (
        1,
        'nima'
    )
   COMMIT TRAN ins
END TRY
BEGIN CATCH
   DECLARE @a  NVARCHAR(1000);
   IF ERROR_NUMBER() = 2627
     RAISERROR(N'Row Exists',16,1);
   ELSE
   BEGIN
     SET @a=ERROR_MESSAGE();
     RAISERROR(@a,16,1);
   END
   ROLLBACK TRAN ins
END CATCH

Я упоминал об этом до

Редактировать: принудительно использовать различные уникальные выражения для SQL Server 2008

Использовать отфильтрованные индексы

CREATE UNIQUE NONCLUSTERED INDEX IX_UniqueF1 ON (City_Code, F1_Code)
   WHERE F2_Code = '' AND F3_Code = '' AND AND F4_Code = 0;

CREATE UNIQUE NONCLUSTERED INDEX IX_UniqueF1 ON (City_Code, F2_Code)
   WHERE F1_Code = '' AND F3_Code = '' AND AND F4_Code = 0;

CREATE UNIQUE NONCLUSTERED INDEX IX_UniqueF3F4 ON (City_Code, F3_Code, F4_Code)
   WHERE F1_Code = '' AND F2_Code = '';

Вы можете сделать то же самое с индексированными представлениями в более ранних версиях

...