Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Параллельная выборка данных двумя или более пользователями / 25 сообщений из 29, страница 1 из 2
23.10.2019, 09:19
    #39880239
Roust_m
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
Добрый день,

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

Пользователь 1 выбирает студентов из школ 1,2 и 3. Пользователь 2 пытается выбрать студентов из школ 3,4 и 5. Поскольку пользователь 1 начал первым, он должен получить список студентов из школ 1, 2 и 3 и пометить их для обработки. Пользователь 2 должен получить студентов только из школ 4 и 5. При этом надо использовать минимально необходимый уровень изоляции. Понятно, что можно залочить всю таблицу и добиться результата, но это не приемлемо.

Я думаю сделать так:
1. Установить уровень изоляции repeatable read
2. Открыть транзакцию
3. Сохранить студентов из школ 1, 2 и 3 в таблицу-переменную
4. В той же транзакции проапдейтить записи студентов со статусом 'S' (чтобы другой пользователь эти записи не трогал)
5. Закомиттить транзакцию.

В это время второй пользователь попытается запустить тот-же код для школ 3,4 и 5. Он не сможет залочить нужные записи и его сессия будет ждать окончания транзакции первого пользователя. Когда первый пользователь закончит свою транзакцию, то студенты школы 3 уже будет помечены статусом 'S' и второй пользователь их не получит.

Подскажите, я мыслю в правильном направлении?

Примерный код ниже.

Спасибо.


Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
DECLARE @json varchar(max) =
N'{
"schoolIds": [1, 2, 3]
}'

DECLARE @studentList TABLE (id bigint)

set transaction isolation level repeatable read
begin tran 
insert into @studentList(id)
select stg_id from stg_student stg 
join openjson(@json,'$.schoolIds') sc on stg.schoolId=value  and ISNULL(status,'') <> 'S' 

update [dbo].[stg_student] set status = 'S' 
from [dbo].[stg_student] s
join @studentList sl
on s.stg_id = sl.id

commit tran
set transaction isolation level read committed
...
Рейтинг: 0 / 0
23.10.2019, 09:43
    #39880263
court
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
Roust_m,

как минимум, эти два запроса
Roust_m
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
insert into @studentList(id)
select stg_id from stg_student stg 
join openjson(@json,'$.schoolIds') sc on stg.schoolId=value  and ISNULL(status,'') <> 'S' 

update [dbo].[stg_student] set status = 'S' 
from [dbo].[stg_student] s
join @studentList sl
on s.stg_id = sl.id


можно объединить в один
Код: sql
1.
2.
3.
4.
5.
update stg 
set stg.status = 'S' 
output inserted.stg_id into @studentList(id)
from stg_student stg 
join openjson(@json,'$.schoolIds') sc on stg.schoolId=value  and ISNULL(status,'') <> 'S'
...
Рейтинг: 0 / 0
23.10.2019, 09:49
    #39880272
Roust_m
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
court,

Хорошо, а как по поводу уровня изоляции? Он достаточный для получения нужного результата? Также не является ли он избыточным?
...
Рейтинг: 0 / 0
23.10.2019, 09:57
    #39880281
TaPaK
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
Roust_m,

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


readpast
...
Рейтинг: 0 / 0
23.10.2019, 10:10
    #39880296
Roust_m
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
TaPaKRoust_m,

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


readpast

Как-то не очень надежно. А вдруг там записи залочены по другой причине (другой операции) и ни один из пользователей их не получит.
...
Рейтинг: 0 / 0
23.10.2019, 10:15
    #39880300
TaPaK
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
Roust_mTaPaKRoust_m,

пропущено...


readpast

Как-то не очень надежно. А вдруг там записи залочены по другой причине (другой операции) и ни один из пользователей их не получит.
repeatable read не обеспечивает праллельную обработку
...
Рейтинг: 0 / 0
23.10.2019, 10:27
    #39880312
invm
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
Roust_m,

Как быть, если один хочет (1, 2, 3), а другой, например, (2, 3)?
...
Рейтинг: 0 / 0
23.10.2019, 10:33
    #39880315
L_argo
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
Пусть юзеры вызывают ХП.
А ХП заносит сделанный выбор в табличку. Другой юзер тоже заносит свой выбор, но только то, чего еще там нет.
Потом селектит только свое вставленное.

Логику можно сделать более сложной.
...
Рейтинг: 0 / 0
23.10.2019, 10:44
    #39880319
invm
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
Roust_m,

В общем, вот вам "рыба", дальше допилите под свои требования:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
begin tran 
insert into @studentList(id)
select stg_id from stg_student stg 
join openjson(@json,'$.schoolIds') sc on stg.schoolId=value  and ISNULL(status,'') <> 'S' 

declare @res nvarchar(255), @result int

declare res cursor local fast_forward for
 select N'school' + cast(id as nvarchar(10)) from @studentList

open res
while 1 = 1
 begin
  fetch next from res into @res
  if @@fetch_status <> 0
   break;

  exec @result = sp_getapplock @res, N'Exclusive', N'Transaction', -1
  if @result <> 0 -- ошибка
   begin
    ...
   end
 end
close res
deallocate res

update [dbo].[stg_student] set status = 'S' 
from [dbo].[stg_student] s
join @studentList sl
on s.stg_id = sl.id

commit tran
...
Рейтинг: 0 / 0
23.10.2019, 10:47
    #39880320
Ftt330
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
Roust_mЕсть такая задача, обеспечить параллельную выборку данных двумя (или более) пользователями, чтобы они не выбрали одни и те же записи для обработки.

Очередь.
...
Рейтинг: 0 / 0
24.10.2019, 00:55
    #39880733
Roust_m
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
invmRoust_m,

Как быть, если один хочет (1, 2, 3), а другой, например, (2, 3)?

Если тот, кто хочет 1,2,3 пришел первым, то второй ничего не получает и должен выбрать что-то другое.
...
Рейтинг: 0 / 0
24.10.2019, 00:57
    #39880734
Roust_m
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
L_argoПусть юзеры вызывают ХП.
А ХП заносит сделанный выбор в табличку. Другой юзер тоже заносит свой выбор, но только то, чего еще там нет.
Потом селектит только свое вставленное.

Логику можно сделать более сложной.

Примерно тоже самое я и пытаюсь сделать. Юзеры заносят выборку в свою таблицу и в общей таблице помечают то что они выбрали, чтобы другие это же не взяли. Просто надо разрулить ситуацию когда они почти одновременно обращаются за выборкой.
...
Рейтинг: 0 / 0
24.10.2019, 00:58
    #39880735
Roust_m
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
Ftt330Roust_mЕсть такая задача, обеспечить параллельную выборку данных двумя (или более) пользователями, чтобы они не выбрали одни и те же записи для обработки.

Очередь.

Не совсем понятно. В какой форме?
...
Рейтинг: 0 / 0
24.10.2019, 01:37
    #39880738
Roust_m
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
invmRoust_m,

В общем, вот вам "рыба", дальше допилите под свои требования:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
begin tran 
insert into @studentList(id)
select stg_id from stg_student stg 
join openjson(@json,'$.schoolIds') sc on stg.schoolId=value  and ISNULL(status,'') <> 'S' 

declare @res nvarchar(255), @result int

declare res cursor local fast_forward for
 select N'school' + cast(id as nvarchar(10)) from @studentList

open res
while 1 = 1
 begin
  fetch next from res into @res
  if @@fetch_status <> 0
   break;

  exec @result = sp_getapplock @res, N'Exclusive', N'Transaction', -1
  if @result <> 0 -- ошибка
   begin
    ...
   end
 end
close res
deallocate res

update [dbo].[stg_student] set status = 'S' 
from [dbo].[stg_student] s
join @studentList sl
on s.stg_id = sl.id

commit tran



Я не совсем понимаю как это работает. Залочить надо таблицу stg_student (желательно не всю, а минимально необходимые записи), после чего выбрать из нее нужные записи и пометить их как выбранные, чтобы следующий пользователь не взял себе те же самые записи.
...
Рейтинг: 0 / 0
24.10.2019, 08:45
    #39880758
L_argo
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
Просто надо разрулить ситуацию когда они почти одновременно обращаются за выборкой. Если это будет делать одна ХП, то коллизий не будет.
...
Рейтинг: 0 / 0
24.10.2019, 08:59
    #39880762
Roust_m
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
L_argoПросто надо разрулить ситуацию когда они почти одновременно обращаются за выборкой. Если это будет делать одна ХП, то коллизий не будет.

Это будет реализовано в одной хранимой процедуре, но запускаться она будет многими пользователями. Почему не будет коллизий?
...
Рейтинг: 0 / 0
24.10.2019, 10:06
    #39880777
invm
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
Roust_mЗалочить надо таблицу stg_studentТаблицу надо не лочить, а сериализовать к ней доступ по определенным критериям. Что данный код и делает на основе пользовательских блокировок.

Если есть справочник школ, то можно еще и так
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
begin tran 
insert into @studentList(id)
select stg_id from stg_student stg 
join openjson(@json,'$.schoolIds') sc on stg.schoolId=value  and ISNULL(status,'') <> 'S' 

declare @c int;
select
 @c = count(*)
from
 @studentList a join
 [Справочник школ] with (rowlock, updlock) b on b.id = a.id;

update [dbo].[stg_student] set status = 'S' 
from [dbo].[stg_student] s
join @studentList sl
on s.stg_id = sl.id

commit tran
...
Рейтинг: 0 / 0
24.10.2019, 10:12
    #39880778
L_argo
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
Roust_mЭто будет реализовано в одной хранимой процедуре, но запускаться она будет многими пользователями. Почему не будет коллизий?Потому что эта процедура сначала вставляет только свое и потом читает только свое.

Шутки ради можно индекс уникальный поставить, чтобы вставить одну и ту же ID два раза было в принципе нельзя. :)
...
Рейтинг: 0 / 0
24.10.2019, 10:15
    #39880781
TaPaK
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
L_argoRoust_mЭто будет реализовано в одной хранимой процедуре, но запускаться она будет многими пользователями. Почему не будет коллизий?Потому что эта процедура сначала вставляет только свое и потом читает только свое.

Шутки ради можно индекс уникальный поставить, чтобы вставить одну и ту же ID два раза было в принципе нельзя. :)
т.е. пусть валится в ошибки это нормально
...
Рейтинг: 0 / 0
24.10.2019, 12:03
    #39880850
Владислав Колосов
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
Roust_m,

вот Вам демо пример реализации.

создаёте сессию 1, копируете пример:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
-- тестовая таблица
create table tempdb.dbo.t1 (id int, val int default 0);
insert tempdb.dbo.t1 (id) values (1),(2),(3),(4),(5);

begin tran
select * from tempdb.dbo.t1 with (readpast); -- первый пользователь выбирает все доступные строки для принятия решения на редактирование
select * from tempdb.dbo.t1 with (updlock,readpast) where id in (1,3); -- забрать строки для редактирования
update tempdb.dbo.t1 with (readpast) set val = 2 where id in (1,3); -- обновить указанные строки

select * from tempdb.dbo.t1 with (readuncommitted);

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

rollback
drop table tempdb.dbo.t1



создаёте сессию 2, имитирующую. работу второго пользователя, та же последовательность запросов, что и для первого:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
begin tran
select * from tempdb.dbo.t1 with (readpast); -- второй пользователь выбирает всё, что не выбрал первый для принятия решения на редактирование
select * from tempdb.dbo.t1 with (updlock,readpast) where id in (2,4); -- забрать строки для редактирования
update tempdb.dbo.t1 with (readpast) set val = 2 where id in (2,4); -- обновить указанные строки

select * from tempdb.dbo.t1 with (readuncommitted); -- просмотреть всю таблицу

rollback
...
Рейтинг: 0 / 0
24.10.2019, 12:06
    #39880857
Владислав Колосов
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
В первом запросе для наглядности лучше указать set val = 1.
...
Рейтинг: 0 / 0
25.10.2019, 05:58
    #39881297
Roust_m
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
Владислав Колосов,

Спасибо, попробую
...
Рейтинг: 0 / 0
25.10.2019, 10:54
    #39881397
invm
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
Roust_mПользователь 1 выбирает студентов из школ 1,2 и 3. Пользователь 2 пытается выбрать студентов из школ 3,4 и 5. Поскольку пользователь 1 начал первым, он должен получить список студентов из школ 1, 2 и 3 и пометить их для обработки. Пользователь 2 должен получить студентов только из школ 4 и 5. При этом надо использовать минимально необходимый уровень изоляции. Понятно, что можно залочить всю таблицу и добиться результата, но это не приемлемо.Каюсь, невнимательно прочитал задачу.
Если есть справочник школ, решается так:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
begin tran

insert into @studentList(id)
select
 stg_id
from
 openjson(@json,'$.schoolIds') scl join
 [Справочник школ] sc with (updlock, readpast) on sc.schoolId = a.value join
 stg_student stg on stg.schoolId = sc.schoolId and ISNULL(stg.status,'') <> 'S' 

update [dbo].[stg_student] set status = 'S' 
from [dbo].[stg_student] s
join @studentList sl
on s.stg_id = sl.id

commit tran
...
Рейтинг: 0 / 0
28.10.2019, 10:22
    #39882201
Roust_m
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
invmRoust_mПользователь 1 выбирает студентов из школ 1,2 и 3. Пользователь 2 пытается выбрать студентов из школ 3,4 и 5. Поскольку пользователь 1 начал первым, он должен получить список студентов из школ 1, 2 и 3 и пометить их для обработки. Пользователь 2 должен получить студентов только из школ 4 и 5. При этом надо использовать минимально необходимый уровень изоляции. Понятно, что можно залочить всю таблицу и добиться результата, но это не приемлемо.Каюсь, невнимательно прочитал задачу.
Если есть справочник школ, решается так:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
begin tran

insert into @studentList(id)
select
 stg_id
from
 openjson(@json,'$.schoolIds') scl join
 [Справочник школ] sc with (updlock, readpast) on sc.schoolId = a.value join
 stg_student stg on stg.schoolId = sc.schoolId and ISNULL(stg.status,'') <> 'S' 

update [dbo].[stg_student] set status = 'S' 
from [dbo].[stg_student] s
join @studentList sl
on s.stg_id = sl.id

commit tran



Даже если объединить два запроса внутри транзакции как предложил court и установить режим изоляции как repeatable read, у меня не получилось разделить пользователей.

Пользователь 1:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
DECLARE @json varchar(max) =
N'{
"schoolIds": [1, 2]
}'


DECLARE @studentList TABLE (id bigint)

set transaction isolation level repeatable read
begin tran 

update stg 
set stg.status = 'S' 
output inserted.stg_id into @studentList(id)
from stg_student stg 
join openjson(@json,'$.schoolIds') sc on stg.schoolId=value  and ISNULL(transferred_status,'') <> 'S'

waitfor delay '00:00:15'

commit tran
set transaction isolation level read committed


select ss.schoolId, sl.id from @studentList sl
join stg_student ss
on sl.id = ss.stg_id




Пользователь 2:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
DECLARE @json varchar(max) =
N'{
"schoolIds": [2, 3]
}'
select ISJSON(@json)

DECLARE @studentList TABLE (id bigint)

set transaction isolation level repeatable read
begin tran 

update stg 
set stg.status = 'S' 
output inserted.stg_id into @studentList(id)
from stg_student stg 
join openjson(@json,'$.schoolIds') sc on stg.schoolId=value  and ISNULL(transferred_status,'') <> 'S'

waitfor delay '00:00:15'

commit tran
set transaction isolation level read committed


select ss.schoolId, sl.id from @studentList sl
join stg_student ss
on sl.id = ss.stg_id



Оба пользователя получают пересекающиеся данные.
...
Рейтинг: 0 / 0
28.10.2019, 10:25
    #39882202
TaPaK
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Параллельная выборка данных двумя или более пользователями
Roust_m,

авторДаже если объединить два запроса внутри транзакции как предложил court и установить режим изоляции как repeatable read, у меня не получилось разделить пользователей.

а точнее сделать всё иначе, то почему-то не работает...
...
Рейтинг: 0 / 0
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Параллельная выборка данных двумя или более пользователями / 25 сообщений из 29, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]