У меня есть SP в SQL Server, который выполняет сотни времен в минуту и должен проверить входящий трафик по базе данных. В данный момент это делает следующее
INSERT INTO table
SELECT @value1,@value2 WHERE NOT EXISTS
(SELECT * FROM table WHERE value1 = @value1 AND value2 = @value2);
Однако я мог также пойти с
IF NOT EXISTS(SELECT * FROM table WHERE value1 = @value1 AND value2 = @value2)
INSERT INTO table (value1,value2) VALUES (@value1,@value2);
Который был бы быстрее? Я получаю чувство, что нет большого различия между ними, но я исторически не очень хорош в TSQL... = /
ОБНОВЛЕНИЕ:Ой... предназначенный, чтобы указать то, что СУЩЕСТВУЕТ, использует больше чем 1 значение, чтобы найти, существует ли запись, таким образом, ограничение на уникальность данных не будет работать. Отредактированный образец для отражения этого...
После добавления газиллиона комментариев к этому вопросу и ответам на него, я попробую ответить на него по-своему.
Я бы не ожидал большой разницы в производительности между двумя предложенными в исходном вопросе подходами. С одной стороны, как указал Рэй, второй подход может избавить вас от необходимости делать некоторые приготовления к вставке, но с другой стороны, РСУБД обычно лучше всего работает с пакетными операторами, как в первом решении.
KM и DVK предлагают добавить ограничение UNIQUE
, которое сделает проверку уникальности неявной, но потребует от вас добавления некоторой обработки ошибок вокруг оператора INSERT
. Мне трудно понять, почему это должно увеличить производительность, предполагая, что у вас уже есть индекс, покрывающий эти два столбца. Если у вас нет такого индекса, добавьте его и пересмотрите потребность в дополнительной производительности.
Явная или неявная проверка уникальности не имеет значения AFAIK. Если что-то и выигрывает от того, что проверка выполняется "внутри" желудка СУБД, то этот выигрыш может быть просто съеден накладными расходами, связанными с возникновением и обработкой ошибок при наличии дубликатов.
Итог: Предполагая, что индекс уже установлен, если вы все еще жаждете производительности, я рекомендую вам провести эмпирические тесты трех предложенных решений. Составьте небольшую программу, имитирующую ожидаемые входные данные, и обработайте каждое из трех решений несколькими миллиардами строк, включая правдоподобное количество дубликатов. сделайте это и не забудьте опубликовать свои результаты :-)
. В среде с ограниченным параллелизмом одновременный INSERT
может произойти между IF NOT EXISTS
и INSERT
во втором запросе.
Ваш первый запрос установит общие блокировки на исследуемую запись, которые не будут сняты до конца запроса, поэтому будет невозможно вставить новую запись, пока запрос не будет запущен.
Однако не следует полагаться исключительно на такое поведение. Установите дополнительное ограничение UNIQUE
на значение
.
Это не только сделает базу данных более согласованной, но и создаст индекс, который сделает первый запрос более быстрым.
Если бы мне пришлось догадаться, я бы предположил, что второй вариант будет быстрее. SQL Server не должен будет выполнять какую-либо настройку для вставки, если существует сбой, в то время как в первом случае он может искать некоторые имена таблиц и полей и подготовиться к вставке, которая никогда не произойдет. Однако я бы попробовал это в анализаторе запросов и посмотрел, что говорит план.
-121--3653357-С главной страницы:
Отправка почты
Для отправки сообщения одному или нескольким пользователям можно вызвать почтовую рассылку с помощью аргументы, которые являются именами люди, которым будет отправлена почта. Ожидается, что пользователь введет его сообщение, последовало «control-D» в начале строки.
Другими словами, mailx считывает содержимое для отправки из стандартного ввода и может быть перенаправлен в обычный режим. Например:
ls -l $HOME | mailx -s "The content of my home directory" someone@email.adr
-121--796045- просто сделайте это и проигнорируйте любую ошибку (предполагает уникальное ограничение на значение)...
BEGIN TRY
INSERT INTO Table (value) VALUES (@value);
END TRY
BEGIN CATCH
PRINT 'it was already in there!'
END CATCH
Так как это выполняется сотни раз в минуту , подсказки блокировки должны быть добавлены к ПО и транзакции, чтобы избежать условия гонки
(SELECT * FROM Table WITH (UPDLOCK, HOLDLOCK) WHERE value = @value);
, однако, моя предложенная идея просто ВСТАВИТЬ и игнорировать любую повторяющуюся ошибку ограничения также позволит избежать условия гонки.
Если вы хотите, чтобы значения были уникальными, почему бы просто не создать уникальное ограничение на значение, выполнить INSERT без SELECT и изящно обработать ошибку нарушения ограничения?
Это будет быстрее, чем любой из этих подходов.
Кроме того, ваш первый подход не работает - к тому времени, как вы доберетесь до select, вы уже вставили значение, поэтому select, очевидно, найдет то, что вы только что вставили.
Если бы мне пришлось угадывать, я бы предположил, что второй вариант был бы быстрее. sql-серверу не нужно будет выполнять какие-либо настройки для вставки, если существует сбой, тогда как в первом он может искать некоторые имена таблиц и полей и готовиться к вставке, которая никогда не происходит. Однако я бы попробовал это в анализаторе запросов и посмотрел, что написано в плане.
Оба варианта неверны. Вы вставите пары повторяющихся @ value1, @ value2, гарантированно .
Правильный способ справиться с этим - наложить уникальное ограничение на два столбца и всегда ВСТАВИТЬ и обработать нарушение ограничения:
ALTER TABLE Table ADD CONSTRAINT uniqueValue1Value UNIQUE (value1, values2);
и вставить:
BEGIN TRY
INSERT INTO Table (value1, value2) VALUES (@value1, @value2);
END TRY
BEGIN CATCH
DECLARE @error_number int, @error_message NVARCHAR(4000), @xact_state INT;
SET @error_number = ERROR_NUMBER();
SET @error_message = ERROR_MESSAGE();
SET @xact_state = XACT_STATE();
IF (@xact_state = -1)
BEGIN
ROLLBACK TRANSACTION;
END
IF (@error_number != 2627) /* 2627 is ' Cannot insert duplicate key in object ...' */
BEGIN
RAISERROR(N'Error inserting into Table: %i %s', 16,1, @errror_number, @error_message);
END
ENd CATCH
Хотя это может показаться сложным, необходимо учесть небольшую деталь, названную корректностью . Это намного проще по сравнению с решением на основе подсказок блокировки. Это также наиболее эффективное решение: выполняет только один поиск. Для всех остальных решений требуется как минимум два поиска (один для проверки возможности вставки, второй для вставки).