2015-09-25 4 views
0

Мне не удалось найти ответ на этот вопрос. Предположим, у меня есть следующая таблица/запрос:Избегайте вставки повторяющихся записей в SQL Server

Стол:

create table ##table 
(
    column1 int, 
    column2 nvarchar(max) 
) 

Запрос (в реальном сценарии жизни состояние будет более сложным):

declare @shouldInsert bit 
set @shouldInsert = case when exists(
    select * 
    from ##table 
    where column2 = 'test') then 1 else 0 end 

--Exaggerating a possible delay: 
waitfor delay '00:00:10' 

if(@shouldInsert = 0) 
    insert into ##table 
    values(1, 'test') 

Если я запускаю этот дважды, тогда он может вставить дубликаты записей (ограничение уникального ограничения не может быть и речи, потому что реальное условие более активно, чем просто уникальность «column1» по всей таблице).

Я вижу два возможных решения:

  1. я бег оба параллельных транзакций в сериализуемой режиме, но это создаст затор (первый общий замок в выбери то х-замок в вкладыше - тупиковый).

  2. В отборном заявлении я использую запрос подсказку с (обновлением, TABLOCK), который будет эффективно рентгеновским заблокировать всю таблицу, но это будет препятствовать другие транзакциям чтения данных (что-то я хотел бы избежать)

Что более приемлемо? Есть ли третье решение?

Спасибо.

+0

Нельзя использовать LEFT JOIN 'insert в ## table SELECT t.col1, t.col2 FROM (SELECT 1 as col1, 'test' as col2) t LEFT JOIN ## table temp ON t.col1 = temp.col1 WHERE temp.col1 IS NULL'? – lad2025

+0

Вы считали объединение теста shouldInsert и фактической вставки в один оператор SQL. Что-то в строках «insert into ## table (выберите 1,« test »из dual, где не существует ...» –

+0

Я бы выбрал второе решение, но с помощью 'INSERT ... SELECT ... WHERE NOT Синтаксис EXISTS с подсказкой блокировки в подзапросе.Я бы не ожидал, что параллелизм будет проблемой, если у вас очень высокая скорость вставки, предполагая уникальный индекс в столбце2. –

ответ

1

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

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

0

Независимо от того, как «вовлечено» в ваше «реальное состояние», у вас есть два варианта: обеспечить UNIQUE или иметь дело с несколькими записями. Любая работа вокруг будет, вероятно, хрупкой.

Например ваш delay хак довольно бесполезно, если вам нужно добавить еще один сервер БД или подавляющую нагрузку замедляет выполнение отдельных нитей

Один из способов, вы могли бы позволить для нескольких копий РЕКОМЕНДУЕМОГО-Be- уникальное значение - создать другую таблицу, которая может выступать в качестве очереди, и не обеспечивает уникальность и серийный рабочий, чтобы удалить его. Или измените структуру данных, чтобы разрешить 1-ко-многим и выбрать первый при запросе. Все еще хак, но по крайней мере не ужасно «креативный», и он не может сломаться.

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