Вставьте проблему параллелизма - многопоточная среда

У меня есть проблема, что та же хранимая процедура вызывается в точно то же время с точно тем же paramenters.

Цель хранимой процедуры состоит в том, чтобы выбрать запись, если она существует или создать и выбрать запись, если она не существует.

Проблема состоит в том, что оба потока проверяют существование записи и сообщают о лжи, и затем оба вставляют новую запись, создавая дубликат в базе данных.

Я пытался засунуть операции в транзакции, но это просто произвело сотни мертвых блокировок.

Есть ли какой-либо способ, которым я могу проверить на существование записи ориентированным на многопотоковое исполнение способом так, чтобы второй поток не делал своего чтения, пока первое не закончило свою вставку? Я не имею никакого контроля над самими потоками, только над сохраненным procs, который они выполняют.

Любая справка ценилась бы,

Спасибо.

6
задан marc_s 24 June 2010 в 10:47
поделиться

3 ответа

Уловка состоит в том, чтобы добавить WHERE к вашему оператору INSERT, чтобы INSERT работал, только если элемент не существует, за которым следует оператор SELECT. Предположив, что запись может быть идентифицирована по столбцу идентификатора, вы должны написать:

INSERT INTO MyTable (ID,Col1,Col2,...) 
SELECT @IDValue,@Col1Value,@Col2Value, ...
WHERE NOT EXISTS (SELECT ID  
              FROM MyTable 
              WHERE ID=@IDValue) 

SELECT *  
FROM MyTable 
Where ID=@IDValue 

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

EDIT : синтаксис INSERT ... SELECT необходим, потому что TSQL не допускает частей VALUES и WHERE в операторе INSERT.

8
ответ дан 16 December 2019 в 21:34
поделиться

Не уверен, есть ли он у SQL Server. Но в MySQL и в Oracle вы можете получить блокировку записи при выборе, используя синтаксис для обновления .

select * 
from table 
for update

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

0
ответ дан 16 December 2019 в 21:34
поделиться

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

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

1) сначала выполните вставку и обработайте исключение или ошибку, если она попытается вставить дубликат

, либо 2) выполните HOLD LOCK (Sybase и SQL Server) при выполнении выбор первым - таким образом, первый блокируемый получает полное разрешение на вставку при необходимости

или 3) Возможно использование команды слияния, если это позволяет СУБД. Это выполняет проверку и вставку все в одной команде, но всегда будет изменять базу данных.

РЕДАКТИРОВАТЬ: Я думаю, что нет реальной альтернативы 1, если вам нужно убедиться, что есть одна и только одна запись, вставленная в качестве проверки, которая должна быть в транзакции.

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

0
ответ дан 16 December 2019 в 21:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: