У меня есть вопрос относительно производительности SQL Server.
Предположим, что у меня есть таблица persons
со следующими столбцами: id
, name
, surname
.
Теперь, я хочу вставить новую строку в эту таблицу. Правило следующее:
Если id
не присутствует в таблице, затем вставьте строку.
Если 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.
Оба работают нормально, но я обычно использую вариант 2 (pre-mssql 2008), так как он читается немного более четко. Я бы не стал особо беспокоиться о производительности ... Если это станет проблемой, вы можете использовать NOLOCK
в предложении exists
. Тем не менее, прежде чем вы начнете использовать NOLOCK повсюду, убедитесь, что вы охватили все свои основы (индексы и вещи, относящиеся к архитектуре большой картины). Если вы знаете, что будете обновлять каждый элемент более одного раза, возможно, стоит рассмотреть вариант 1.
Вариант 3 - не использовать деструктивные обновления. Это требует больше работы, но в основном вы вставляете новую строку каждый раз при изменении данных (никогда не обновляете и не удаляете из таблицы) и имеете представление, которое выбирает все самые последние строки. Это полезно, если вы хотите, чтобы таблица содержала историю всех своих предыдущих состояний, но это также может быть излишним.
Вариант 1 кажется удачным. Однако, если вы используете SQL Server 2008, вы также можете использовать MERGE , который может хорошо работать для таких задач UPSERT.
Обратите внимание, что вы можете использовать явную транзакцию и параметр XACT_ABORT для таких задач, чтобы согласованность транзакции сохранялась в случае проблемы или одновременного изменения.
Я склонен использовать вариант 1. Если в таблице есть запись, вы экономите один поиск. Если нет, то вы ничего не теряете. Более того, во втором варианте вы можете столкнуться с забавными проблемами блокировки и тупика, связанными с несовместимостью блокировок. Более подробная информация есть в моем блоге:
http://sqlblogcasts.com/blogs/piotr_rodak/archive/2010/01/04/updlock-holdlock-and-deadlocks.aspx