2013-06-06 6 views
1

Установка: SQL Server 2008 R2MS SQL индекс обновления значение

предыстория: У нас есть прок, который вызывается в несколько потоков одновременно. Эти потоковые запросы proc иногда записывают перекрывающиеся (дублированные) данные в таблицу, в которую они записываются. В инструкции insert у меня есть предложение NOT NOT EXISTS, чтобы убедиться, что дубликаты не вставлены, но мы все равно получаем дубликаты.

Вопрос: «НЕ СУЩЕСТВУЕТ» оговорка делает простой выбор, это возможно, так как вставки для резьбовых вызовов только миллисекунды друг от друга, что некоторые из индексов (в частности, те, которые используются «НЕ EXISTS ") еще не обновлены? Поэтому перед выполнением вставки она не видит существующей записи?

Мысли: Это может быть я, не понимающий, как SQL тоже делает свою вещь. Если у меня есть вставка с «WHERE NOT EXISTS», проверяется ли она, чтобы убедиться, что ни одна из записей не существует перед выполнением вставки? Или он проверяет строку за строкой, как она вставляет каждую строку? Если это первый (проверяя все, прежде чем делать какую-либо вставку), то я полагаю, что один из других вызовов еще не завершил его вставку.

Я в тупик.

Вот пример того, что я делаю:

INSERT INTO [SomeTable] (Col1,Col2) 
SELECT 
    ColumnA, 
    ColumnB 
FROM 
    #TempTable 
WHERE 
    NOT EXISTS (
     SELECT 1 
     FROM [SomeTable] 
     WHERE Col1 = #TempTable.ColumnA 
       AND Col2 = #TempTable.ColumnB 
    )
+0

Не могли бы вы показать нам код? Угадывание занимает слишком много времени. См. [Написание идеального вопроса] (http://tinyurl.com/so-hints). – HABO

+0

Используете ли вы транзакции в своем коде? –

+0

Нет транзакций, а proc - 10 000 строк. :) Это прямая вставка, хотя она вставляет записи из таблицы temp в пользовательскую таблицу, где запись еще не существует. Если вы запустите proc для сотрудника, затем запустите его снова сразу после этого, он ничего не вставляет, поскольку он видит, что записи уже есть. 'Test' –

ответ

0

Вы должны блокировать таблицу на время сделки. Другие потоки будут ждать завершения транзакции (фиксация или откат).

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ 

BEGIN TRANSACTION 

--do stuff 

COMMIT TRANSACTION 

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

+0

Поскольку ОП проверяет существование, ему также необходимо блокировать несуществующую строку. 'REPEATABLE READ' не предоставляет этого. –

+0

Ах да, поэтому я вижу. –

0

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

Это означает, что после завершения SELECT и до того, как произойдет INSERT, другой поток может вставить строку, даже если этот пробел составляет всего несколько наносекунд.

Даже оператор MERGE не предотвращает одновременные вставки, так как между частью поиска и частью вставки существует некоторое время. (См. http://sqlity.net/en/1645/merge-wonders-insert-or-use/ для получения более подробной информации.)

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

Что-то вроде:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; 
BEGIN TRAN 
    IF(NOT EXISTS(SELECT ...)) 
    BEGIN 
    INSERT.... 
    END; 
COMMIT; 

UPDATE:

Поскольку вы предоставили пример сейчас пытается сделать два шаг вместе, позволь мне вновь опубликовать мой пример из ссылочных статей со всеми материал, который не имеет значения для этого случая:

MERGE dbo.Product WITH(HOLDLOCK) AS p 
USING (VALUES(@ProductName, @ProductNumber))n(Name,ProductNumber) 
ON p.ProductNumber = n.ProductNumber 
WHEN NOT MATCHED THEN 
INSERT(Name, ProductNumber) 
VALUES(n.Name, n.ProductNumber) 

HOLDLOCK Подсказка имеет (локально) тот же эффект, что и установка уровня изоляции транзакции до SERIALIZABLE. Поскольку MERGE является оператором изменения данных, он автоматически выполняется в транзакции.

Использование инструкции MERGE имеет дополнительное преимущество, что вы можете легко добавить ветку UPDATE, если это возникнет позже.

+0

Я сделаю некоторое исследование по этому варианту. Благодаря! –

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