2014-02-21 3 views
-2

У меня есть таблица «INSERTIF», который выглядит следующим образом -Безопасный способ потока, чтобы проверить, существует ли строка перед вставкой. Правильно ли мой код?

id value 
S1 s1rocks 
S2 s2rocks 
S3 s3rocks 

Перед вставкой строки в эту таблицу, я хотел бы проверить, если данный идентификатор существует или нет. Если он не существует, тогда вставьте. Else, просто обновите значение. Я хочу сделать это безопасным потоком. Можете ли вы сказать, правильно ли мой код или нет? Я попробовал, и это сработало. Но я хочу быть уверенным, что у меня нет недостатка в производительности.

EDIT 1- Я хочу использовать этот код для вставки миллионов строк по одному. Каждый оператор insert обернут вокруг кода, который я показал.

EDIT 2 - Я не хочу использовать часть UPDATE моего кода, достаточно только вставки.

Я не хочу использовать MERGE, поскольку он работает только с SQL Server 2008 и выше

Спасибо.

код -

-- no check insert 
INSERT INTO INSERTIF(ID,VALUE) 
VALUES('S1', 's1doesNOTrock') 

--insert with checking 

begin tran /* default read committed isolation level is fine */ 
if not exists 
(select * from INSERTIF with (updlock, rowlock, holdlock) 
where ID = 'S1') 
BEGIN 
INSERT INTO INSERTIF(ID,VALUE) 
VALUES('S1', 's1doesNOTrock') 
END 
else 
/* update */ 
UPDATE INSERTIF 
SET VALUE = 's1doesNOTrock' 
WHERE ID = 'S1' 
commit /* locks are released here */ 

код для создания таблицы -

CREATE TABLE [dbo].[INSERTIF](
    [id] [varchar](50) NULL, 
    [value] [varchar](50) NULL 
) 
INSERT [dbo].[INSERTIF] ([id], [value]) VALUES (N'S1', N's1rocks') 
INSERT [dbo].[INSERTIF] ([id], [value]) VALUES (N'S2', N's2rocks') 
INSERT [dbo].[INSERTIF] ([id], [value]) VALUES (N'S3', N's3rocks') 
+1

@JonathanLeffler - см. Мое редактирование. Я НЕ хочу использовать MERGE. Я просто этого не делаю. – Steam

+4

Выполнение этого для миллиона строк «по одному» является безумным. См. Http://stackoverflow.com/questions/12621241/can-i-use-the-merge-statement-in-sql-server-2005. Вставьте в таблицу temp и используйте принятый ответ. –

+1

OK; SQL Server 2005 почти десятилетие назад; возможно, ваши пользователи должны обновлять до 6-летней версии? Зачем калечить ваши современные системы, чтобы вы все еще могли работать с архаичными? Заявление MERGE может дать вам прирост производительности по эффективности - особенно если код, который у вас есть, включает в себя удаление данных из СУБД клиенту и обратно. –

ответ

5

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

У вас есть (небольшое) окно уязвимости из-за проблемы TOCTOU (время проверки, времени использования) между вашим «не существует» SELECT и соответствующим действием. Предполагая, что у вас есть уникальное (основное) ограничение ключа в столбце id, вы должны использовать парадигму «Легче, чтобы попросить прощение, чем разрешение», а не парадигму «Взгляд перед прыжком» (см. EAFP vs LBYL).

Это означает, что вы должны определить, какая из двух операций последовательностей вы собираетесь использовать:

  1. INSERT, UPDATE, но если это не удается.
  2. UPDATE, но INSERT, если строки не обновлены.

Либо работает. Если работа будет в основном вставляться и время от времени обновляться, то 1 лучше, чем 2; если работа будет в основном обновляться с помощью случайной вставки, то 2 лучше, чем 1.Вы можете даже работать адаптивно; следите за тем, что произошло в последних N строках (где N может быть всего 5 или целых 500), и используйте эвристику, чтобы решить, что попробовать в новой строке. Там может быть проблема, если INSERT терпит неудачу (поскольку существовала строка), но UPDATE ничего не обновляет (поскольку кто-то удалил строку после неудачной вставки). Аналогичным образом, все еще может быть проблема с UPDATE и INSERT (ни одна строка не существует, но одна была вставлена).

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

Вам также необходимо рассмотреть свой уровень изоляции, который может изменить исходный ответ. Если ваша изоляция достаточно высока, чтобы гарантировать, что после выполнения «не существует» SELECT никто другой не сможет вставить строку, которую вы определили, не существует, тогда вы можете быть в порядке. Это приводит к некоторому пониманию вашей СУБД (и я не эксперт по SQL Server).

Вам также необходимо подумать о границах транзакций; насколько велика сделка, особенно если исходные данные имеют миллион записей.

+0

Я ничего не знаю об уровнях изоляции. Я слышу об этом в первый раз. Прямо сейчас, опция UPDATE не нужна для меня. Должен ли я иметь транзакцию для каждой строки или для партии строк (при проверке существования каждой строки, которую я хочу вставить)? Благодарю. – Steam

+1

Это балансирующий акт; это зависит от требований. Я был бы склонен кодировать настраиваемый размер партии, начиная с, возможно, 64, может быть 1024 операций, а затем посмотреть, как это работает. –

+1

Это потокобезопасность из-за трех намеков блокировки. В частности, 'holdlock' [дает сериализуемую семантику] (http://technet.microsoft.com/en-us/library/ms187373.aspx) и предотвращает фантомы. Я не согласен с подходящим подходом для вставки такого большого количества строк. –

1

Этот метод, как правило, под названием UPSERT. Это можно сделать в SQL Server, используя MERGE. Это работает так:

MERGE INTO A_Table 
USING 
    (SELECT 'data_searched' AS Search_Col) AS SRC 
    -- Search predicates 
    -- 
    ON A_Table.Data = SRC.Search_Col 
WHEN MATCHED THEN 
    -- Update part of the 'UPSERT' 
    -- 
    UPDATE SET 
     Data = 'data_searched_updated' 
WHEN NOT MATCHED THEN 
    -- INSERT part of the 'UPSERT' 
    -- 
    INSERT (Data) 
    VALUES (SRC.Search_Col);  

Также см http://www.sergeyv.com/blog/archive/2010/09/10/sql-server-upsert-equivalent.aspx

EDIT: Я вижу, что вы используете старую SQL Server. В этом случае вы должны использовать несколько операторов.

+0

Мне не нужен MERGE или UPSERT. Не могли бы вы рассказать мне, мой код в порядке или нуждается в модификации? Благодарю. – Steam

Смежные вопросы