SQL Server 2005 - Вставьте, если не существует - PullRequest
7 голосов
/ 25 мая 2011

В Интернете много информации об этой общей "проблеме".

Решения типа:

IF NOT EXISTS() BEGIN INSERT INTO (...) END

, на мой взгляд, не являются поточно-ориентированными, и вы, вероятно, согласитесь.

Однако не могли бы вы подтвердить, что включение существующего в предложение where одного-единственного выбора решило бы проблему наивысшего параллелизма в движке SQL?Достаточно ли этого?

insert into Table (columns)
select column1, column2, column3
where not exists (select top 1 1 from Table where something)

Должен ли быть также добавлен некоторый более высокий уровень транзакции или это может быть выполнено на уровне по умолчанию: commit?

Будет ли это работать на уровне незафиксированного уровня?

Спасибо!

// Добавлено позже

Могу ли я предположить, что оба sql 'верны:

1) установить повторяемость чтения уровня изоляции транзакции

   IF NOT EXISTS() BEGIN INSERT INTO (...) END

2) установить повторяемость чтения уровня изоляции транзакции

insert into Table (columns)
select column1, column2, column3
where not exists (select top 1 1 from Table where something)

Ответы [ 2 ]

6 голосов
/ 25 мая 2011

С TRY / CATCH вы можете избежать дополнительного чтения

BEGIN TRY
   INSERT etc
END TRY
BEGIN CATCH
    IF ERROR_NUMBER() <> 2627
      RAISERROR etc
END CATCH
  • A NOT EXISTS прочтет таблицу, будь то в IF или WHERE
  • INSERT требует чтения для проверки уникальности

Если вы можете отбросить дубликаты, это очень масштабируемая техника

Ссылки:

1 голос
/ 25 мая 2011

Для ответа на обновленный вопрос repeatable read все равно будет недостаточно.

Вам понадобится уровень holdlock / serializable.

Вы пытаетесь предотвратить фантомы (если при первом чтении ни одна строка не соответствовала критериям, поэтому NOT EXISTS возвращает значение true, но впоследствии параллельная транзакция вставляет соответствующую ей строку)

...