Добро пожаловать в форум, Guest >> Войти | Регистрация | Поиск | Правила | | В избранное | Подписаться | ||
Все форумы / Microsoft SQL Server |
![]() ![]() |
Топик располагается на нескольких страницах: [1] 2 3 вперед Ctrl→ все |
Михаил1989
Guest |
есть таблица t(id int, d varchar(10)); нужно написать процедуру, которая принимает на вход параметры @p_id, @p_d и если строка с id = @p_id существует, то сделать update, иначе insert. процедура будет вызываться очень часто (с этим ничего не поделаешь). Как сделать красиво и правильно? merge? Ведь если сделать: if(exists(select 1 from t where id = @p_id)) then begin update... end else if insert... end; То может быть ситуация, когда между select и insert уже кто-то сделал insert... |
11 янв 14, 22:08 [15402879] Ответить | Цитировать Сообщить модератору |
alexeyvg Member Откуда: Moscow Сообщений: 31778 |
begin transaction update ... if @@rocount = 0 insert... commit transaction И кроме того, вместо insert...update можно использовать собственно инструкцию merge |
||
11 янв 14, 22:15 [15402909] Ответить | Цитировать Сообщить модератору |
Михаил1989
Guest |
Спасибо за ответ. А разве между if и insert, нельзя будет сделать insert из другой сессии? Ведь update не встретив строк не наложит никаких блокировок... еще забыл сказать уровень изоляции read committed. |
||
11 янв 14, 22:20 [15402932] Ответить | Цитировать Сообщить модератору |
iap Member Откуда: Москва Сообщений: 47045 |
![]() Между которыми тоже кто-то может сделать INSERT Только эксклюзивная блокировка на чтение спасёт. Но разве это будет жизнь? |
||||
11 янв 14, 22:21 [15402940] Ответить | Цитировать Сообщить модератору |
pkarklin Member Откуда: Москва (Муром) Сообщений: 74925 |
Интересно, а зачем читать, если все равно надо писАть?! |
11 янв 14, 22:23 [15402948] Ответить | Цитировать Сообщить модератору |
alexeyvg Member Откуда: Moscow Сообщений: 31778 |
Нужно видимо так: if(exists(select * from T with(rowlock, SERIALIZABLE ) where id = @id)) или соответственно так: update T with(rowlock, SERIALIZABLE ) ... |
||
11 янв 14, 22:35 [15402998] Ответить | Цитировать Сообщить модератору |
Михаил1989
Guest |
create table rrr1(id int, data varchar(10)); go create unique clustered index uidx_rrr1 on rrr1(id); go set showplan_text on; go begin transaction; merge into rrr1 as trgt using (select 1, '12345') as src(id, data) on trgt.id = src.id when matched then update set trgt.data = src.data when not matched then insert(id, data) values(src.id, src.data); rollback transaction; go set showplan_text off; go а если так, только вместо констант передавать параметры процедуры?
|
11 янв 14, 22:41 [15403037] Ответить | Цитировать Сообщить модератору |
pkarklin Member Откуда: Москва (Муром) Сообщений: 74925 |
Интересный способ отслеживания накладываемых блокировок планом выполнения. |
11 янв 14, 22:47 [15403069] Ответить | Цитировать Сообщить модератору |
iap Member Откуда: Москва Сообщений: 47045 |
Если двое одновременно узнают, что такой записи нет, то оба будут пытаться вставить. Но повезёт только первому! |
||
11 янв 14, 22:51 [15403084] Ответить | Цитировать Сообщить модератору |
Михаил1989
Guest |
|
|||
11 янв 14, 23:04 [15403154] Ответить | Цитировать Сообщить модератору |
pkarklin Member Откуда: Москва (Муром) Сообщений: 74925 |
Спасибо! Вопрос был риторическим, и был обращён к автору топика с целью навести на мысли. |
||
11 янв 14, 23:05 [15403158] Ответить | Цитировать Сообщить модератору |
pkarklin Member Откуда: Москва (Муром) Сообщений: 74925 |
Михаил1989, Вы умеете пользоваться профайлером. Похвально! |
11 янв 14, 23:06 [15403164] Ответить | Цитировать Сообщить модератору |
Михаил1989
Guest |
pkarklin, может мысли на которые я должен был натолкнуться озвучите? |
11 янв 14, 23:14 [15403211] Ответить | Цитировать Сообщить модератору |
pkarklin Member Откуда: Москва (Муром) Сообщений: 74925 |
Михаил1989, Мысли у Вас были правильные в самом начале:
Проверять их правоту следует запустив несколько (пару сотен) вызовов одновременно, а не использовать профайлер. |
||
11 янв 14, 23:19 [15403227] Ответить | Цитировать Сообщить модератору |
Oblom Member Откуда: Moscow Square Сообщений: 627 |
А разве весь MERGE выполняется не в одной транзакции? Или наложение блокировки на вставку производится только перед выполнением INSERT, а не перед селкетом внутри MERGE? Пробовал выяснить в доке, но не нашел, если есть где-то описание наложения блокировок во время MERGE - киньтесь пожалуйста. |
||||
12 янв 14, 01:31 [15403667] Ответить | Цитировать Сообщить модератору |
leov Member Откуда: С-Петербург Сообщений: 616 |
Михаил1989, на мой взгляд вот так это пишется insert t(id,d) select @p_id, @p_d where not exists(select 1 from t where id = @p_id) update t set d=@p_d where id = @p_id |
12 янв 14, 02:15 [15403751] Ответить | Цитировать Сообщить модератору |
alexeyvg Member Откуда: Moscow Сообщений: 31778 |
Без блокировки не обойтись... |
||
12 янв 14, 12:35 [15404236] Ответить | Цитировать Сообщить модератору |
Михаил1989
Guest |
alexeyvg, merge работает как надо |
12 янв 14, 13:25 [15404360] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9632 |
|
||
12 янв 14, 13:36 [15404387] Ответить | Цитировать Сообщить модератору |
leov Member Откуда: С-Петербург Сообщений: 616 |
если моя вставка прошла то никакая другая аналогичная уж точно не пройдет |
||||
12 янв 14, 14:13 [15404468] Ответить | Цитировать Сообщить модератору |
Михаил1989
Guest |
RangeI-N разве не оно? вчера вроде тестировал несколько сессий которые долбят один и тот же merge параллельно - нормально. ни разу duplicate key не вылетело. и одна строка в таблице так и осталась. |
|||||||||||||||||||||||
12 янв 14, 14:42 [15404529] Ответить | Цитировать Сообщить модератору |
Михаил1989
Guest |
и вылетит с ошибкой. а должна понять что надо стать апдейтом. |
||||
12 янв 14, 14:43 [15404534] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9632 |
Вы почему-то считаете, что insert в разных сеансах выстроятся в очередь, а это не так. |
||
12 янв 14, 14:47 [15404541] Ответить | Цитировать Сообщить модератору |
invm Member Откуда: Москва Сообщений: 9632 |
В первом сеансе получите нарушение PK. А потом выполните тоже самое, но с хинтом serializable. Код tools.clrfnWT_Delay не привожу. Вместо нее можете написать свою скалярную функцию, обеспечивающую приемлемую задержку. |
|||||||
12 янв 14, 15:04 [15404574] Ответить | Цитировать Сообщить модератору |
Михаил1989
Guest |
invm, спасибо, добрый человек. мдя. |
12 янв 14, 15:13 [15404583] Ответить | Цитировать Сообщить модератору |
Топик располагается на нескольких страницах: [1] 2 3 вперед Ctrl→ все |
Все форумы / Microsoft SQL Server | ![]() |