Як IDENTITY_INSERT впливає на одночасність?


11

Я намагаюся допомогти клієнтові з додатком сторонніх програм SAP, який має проблему з публікацією та вийшов із-за підтримки.

За певних обставин він зберігає архіви та неповну публікацію з таблиці черги проводки до таблиці архіву публікацій. Мені потрібно перенести ці архівовані результати назад у чергу.

Ідентифікатор черги - це стовпець ідентичності, і я хотів би зберегти її однаковою.

Питання полягає в тому, що якщо я вимкнути ident_insert увімкнено / вставити / ідентифікатор_інсерт, що я можу очікувати щодо одночасності з процесами, які створюють записи черги і очікують, що стовпець ідентифікації буде генерований автоматично?

Будемо дуже вдячні також будь-які вказівки на найкращий спосіб продемонструвати таку поведінку.

Відповіді:


8

Налаштування IDENTITY_INSERT ONсамостійно не усуває одночасність - це не ставить на столі жодних ексклюзивних замків, лише короткий замок стабільності схеми (Sch-S).

Отже, що теоретично може статися за поведінки за замовчуванням, це ви могли зробити це на сеансі 1:

BEGIN TRANSACTION;

-- 1
SET IDENTITY_INSERT dbo.tablename ON;

-- 2
INSERT dbo.tablename(id, etc) VALUES(100, 'foo'); -- next identity is now 101

-- 3
INSERT dbo.tablename(id, etc) VALUES(101, 'foo'); -- next identity is now 102

-- 4
SET IDENTITY_INSERT dbo.tablename OFF;

COMMIT TRANSACTION;

В іншому сеансі ви можете вставити рядки в таблицю в точках 1, 2, 3 або 4. Це може здатися гарною справою, за винятком того, що трапляється з будь-якою вставкою, яка відбувається між 2 і 3, це те, що спрацьовує автоматично створене значення іншим сеансом базується на результатах оператора 2 - таким чином, він генерує 101, і тоді оператор 3 завершиться невдачею з порушенням первинного ключа. Це досить просто, щоб налаштувати і протестувати себе за допомогою деяких WAITFORs:

-- session 1
-- DROP TABLE dbo.what;
CREATE TABLE dbo.what(id INT IDENTITY PRIMARY KEY);
GO
BEGIN TRANSACTION;

SET IDENTITY_INSERT dbo.what ON;

INSERT dbo.what(id) VALUES(32);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(33);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(34);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(35);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(36);

SET IDENTITY_INSERT dbo.what OFF;

COMMIT TRANSACTION;

Після запуску цієї партії запустіть цю партію в іншому вікні:

-- session 2
INSERT dbo.what DEFAULT VALUES;
WAITFOR DELAY '00:00:01';
GO 20

Сесія 2 повинна коли-небудь вставляти значення від 1 до 20, правда? За винятком того, що основна ідентифікація була оновлена ​​вашими ручними вставками сеансу 1, у якийсь момент сеанс 2 підбере місце, де сеанс 1 припинено, і вставить 32, або 33, або 34 тощо. Це буде дозволено, тоді сеанс 1 завершиться невдачею на наступній вставці з порушенням ПК (яке виграш може бути лише питанням часу).

Один із способів вирішити це - викликати TABLOCKна першій вставці:

INSERT dbo.what WITH (TABLOCK) (id) VALUES(32);

Це заблокує будь-яких інших користувачів, які намагаються вставити (або зробити що-небудь справді) в цю таблицю, поки не закінчите переміщення цих заархівованих рядків назад. Це стримує паралельність, звичайно, але саме так ви хочете, щоб блокування працювало. І сподіваємось, це не те, що відбувається з такою частою швидкістю, коли ти весь час блокуєш інших людей.

Кілька інших способів вирішення:

  • перестаньте дбати про IDENTITYстворене значення. Кого хвилює? Використовуйте UNIQUEIDENTIFIER(можливо, згенеровану в окремій таблиці із IDENTITYсурогатом), якщо вихідне значення є дуже важливим.
  • змінити процес архівації на "м'яке видалення", коли щось позначено як архівоване спочатку, а архів не буде постійним до деякої пізнішої дати. Тоді будь-який процес намагається повернути їх назад, можна просто здійснити пряме оновлення та виправити м'який прапор видалення.

Дякую за ваше пояснення. Я пишу автономну утиліту для допомоги з продуктом, який не підтримується, який створює ці поля ідентичності. Я не маю контролю над тим, як це працює.
Метафора
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.