T-SQL вставить или обновить
у меня вопрос относительно производительности 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.
5 ответов
оба работают нормально, но я обычно использую вариант 2 (pre-mssql 2008), так как он читает немного более четко. Я бы тоже не стал говорить о выступлении здесь...Если это становится проблемой, вы можете использовать NOLOCK
на exists
предложения. Хотя, прежде чем вы начнете использовать nolock везде, убедитесь, что вы охватили все свои базы (индексы и архитектуру больших изображений). Если вы знаете, что будете обновлять каждый элемент более одного раза, то может потребоваться рассмотреть вариант 1.
Вариант 1 кажется хорошим. Однако, если вы находитесь на SQL Server 2008, вы также можете использовать слияние, который может выполнять хорошо для таких задач UPSERT.
обратите внимание, что вы можете использовать явную транзакцию и параметр xact_abort опция для таких задач, так что согласованность транзакций остается в случае проблемы или параллельного изменения.
Я склонен использовать Вариант 1. Если в таблице есть запись, вы сохраняете один поиск. Если нет, вы ничего не потеряете. Кроме того, во втором варианте вы можете столкнуться с забавными проблемами блокировки и блокировки, связанными с несовместимостью блокировок. В моем блоге есть дополнительная информация:
http://sqlblogcasts.com/blogs/piotr_rodak/archive/2010/01/04/updlock-holdlock-and-deadlocks.aspx
стремясь быть немного более сухим, я избегаю написания списка значений дважды.
begin tran
insert into persons (id)
select @p_id from persons
where not exists (select * from persons where id = @p_id)
update persons
set name=@p_name, surname=@p_surname
where id = @p_id
commit
колонки name
и surname
должно быть nullable.
сделки означает, что никакой другой пользователь никогда не увидит "пустой" записи.
Edit: cleanup
вы можете просто использовать @@RowCount, чтобы увидеть, сделало ли обновление что-нибудь. Что-то вроде:
UPDATE MyTable
SET SomeData = 'Some Data' WHERE ID = 1
IF @@ROWCOUNT = 0
BEGIN
INSERT MyTable
SELECT 1, 'Some Data'
END