Что является лучшим выбором в delete-insert против if-update else-insert? - PullRequest
6 голосов
/ 02 декабря 2010

Обновление :

Мое плохое ... У меня есть первичный ключ для этих таблиц ... Я не имел в виду дальнейшую индексацию таблиц.Это может произойти в будущем, когда мы увидим производительность, и поскольку у нас слишком много фильтров для данных при извлечении данных, это не показало значительных улучшений при индексировании в прошлый раз, когда мы запускали настройку базы данных.4 огромных таблицы над миллионами записей.Теперь есть хранимая процедура, которая часто вызывается и обновляет эти таблицы.Вот сценарий -

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

Первый путь -

IF EXISTS(TABLE1)
--UPDATE where condn
ELSE
--INSERT
IF EXISTS(TABLE2)
--UPDATE where condn
ELSE
--INSERT
IF EXISTS(TABLE3)
--UPDATE where condn
ELSE
--INSERT
IF EXISTS(TABLE4)
--UPDATE where condn
ELSE
--INSERT

Второй путь -

DELETE from TABLE1 where condn
DELETE from TABLE2 where condn
DELETE from TABLE3 where condn
DELETE from TABLE4 where condn

INSERT TABLE1 ENTRY
INSERT TABLE2 ENTRY
INSERT TABLE3 ENTRY
INSERT TABLE4 ENTRY

Теперь второй способ выглядит проще, но он может занять больше времени ... Я не уверен, какой путь лучше здесь.Может ли кто-нибудь помочь или направить меня сюда ... спасибо!

Ответы [ 3 ]

7 голосов
/ 02 декабря 2010

Если вы ожидаете в основном вставки, попробуйте это

...
BEGIN TRY
   INSERT table1
END TRY
BEGIN CATCH
   IF ERROR_NUMBER = 2627
       UPDATE table1
   ELSE
       --process real error
END CATCH
...

В основном обновления ...

...
BEGIN TRY
   UPDATE table1 ... WHERE ...
   IF @@ROWCOUNT = 0
      INSERT Table1
END TRY
BEGIN CATCH
   --optional. if someone manages to insert before here, do we update it? or just ignore it?
   IF ERROR_NUMBER = 2627
       UPDATE table1
   ELSE
       --process real error
END CATCH
...

EXISTS недостаточно одновременен при высоких нагрузках. Если вы собираетесь сканировать таблицу с помощью EXISTS, вы все равно можете просто попробовать ВСТАВИТЬ.

Другие ответы: Один , Два , Три

Редактировать: я называю это паттерном JFDI ...

2 голосов
/ 02 декабря 2010

Подход if-существующие-then-update-else-insert может содержать больше кода, чем delete-insert , но (в зависимости от того, сколько и какие индексы определены на столах) это намного меньше работы для сервера.

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

Таким образом, если вы не измените каждое индексированное поле записи с вашими обновлениями, более длинный подход будет более эффективным.


РЕДАКТИРОВАТЬ: Обновление вашего вопроса говорит, что в настоящее время у вас нет никаких индексов, кроме первичного ключа (который я предполагаю, является кластеризованным ключом). Итак, для сравнения:

Когда строка уже существует, это 1 поиск кластеризованного индекса (при условии, что вы находите записи по их PK) и:

  • delete-insert : 4 операции записи (удаление строки, удаление строки индекса PK, вставка строки, вставка строки индекса PK)
  • проверка-обновление / вставка : 1 операция записи (строка обновления)

Когда строка еще не существует, это 1 поиск кластеризованного индекса и:

  • delete-insert : 2 операции записи (вставка строки, вставка индексной строки PK)
  • проверка-обновление / вставка : 2 операции записи (вставка строки, вставка строки индекса PK)

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

1 голос
/ 02 декабря 2010

попробуйте это:

UPDATE TABLE1 where condn
IF @@ROWCOUNT=0
    INSERT TABLE1....

UPDATE TABLE2 where condn
IF @@ROWCOUNT=0
    INSERT TABLE2....

UPDATE TABLE3 where condn
IF @@ROWCOUNT=0
    INSERT TABLE3....

UPDATE TABLE4 where condn
IF @@ROWCOUNT=0
    INSERT TABLE4....

не уверен, сработает ли это (вопрос не содержит достаточно информации):

UPDATE TABLE1 where condn
IF @@ROWCOUNT=0
BEGIN
    INSERT TABLE1....
    INSERT TABLE2....
    INSERT TABLE3....
    INSERT TABLE4....
END
ELSE
BEGIN
    UPDATE TABLE2 where condn
    UPDATE TABLE3 where condn
    UPDATE TABLE4 where condn
END
...