T-SQL Вставляет или обновляет

У меня есть вопрос относительно производительности SQL Server.

Предположим, что у меня есть таблица persons со следующими столбцами: id, name, surname.

Теперь, я хочу вставить новую строку в эту таблицу. Правило следующее:

  1. Если id не присутствует в таблице, затем вставьте строку.

  2. Если id присутствует, затем обновите.

У меня есть два решения здесь:

Во-первых:

update persons
  set id=@p_id, name=@p_name, surname=@p_surname
where id=@p_id
if @@ROWCOUNT = 0 
  insert into persons(id, name, surname)
  values (@p_id, @p_name, @p_surname)

Во-вторых:

if exists (select id from persons where id = @p_id)
  update persons
    set id=@p_id, name=@p_name, surname=@p_surname
  where id=@p_id
else
  insert into persons(id, name, surname)
  values (@p_id, @p_name, @p_surname)

Что такое лучший подход? Походит во втором выборе, обновлять строку, это должно искаться два раза, тогда как в первой опции - только однажды. Там какие-либо другие решения к проблеме? Я использую MS SQL 2000.

33
задан mustaccio 29 July 2015 в 23:09
поделиться

3 ответа

Оба работают нормально, но я обычно использую вариант 2 (pre-mssql 2008), так как он читается немного более четко. Я бы не стал особо беспокоиться о производительности ... Если это станет проблемой, вы можете использовать NOLOCK в предложении exists . Тем не менее, прежде чем вы начнете использовать NOLOCK повсюду, убедитесь, что вы охватили все свои основы (индексы и вещи, относящиеся к архитектуре большой картины). Если вы знаете, что будете обновлять каждый элемент более одного раза, возможно, стоит рассмотреть вариант 1.

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

9
ответ дан 27 November 2019 в 19:30
поделиться

Вариант 1 кажется удачным. Однако, если вы используете SQL Server 2008, вы также можете использовать MERGE , который может хорошо работать для таких задач UPSERT.

Обратите внимание, что вы можете использовать явную транзакцию и параметр XACT_ABORT для таких задач, чтобы согласованность транзакции сохранялась в случае проблемы или одновременного изменения.

12
ответ дан 27 November 2019 в 19:30
поделиться

Я склонен использовать вариант 1. Если в таблице есть запись, вы экономите один поиск. Если нет, то вы ничего не теряете. Более того, во втором варианте вы можете столкнуться с забавными проблемами блокировки и тупика, связанными с несовместимостью блокировок. Более подробная информация есть в моем блоге:

http://sqlblogcasts.com/blogs/piotr_rodak/archive/2010/01/04/updlock-holdlock-and-deadlocks.aspx

4
ответ дан 27 November 2019 в 19:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: