Помогите построить логику работы с БД и ее локом (многопоток)

backoff

Client
Регистрация
20.04.2015
Сообщения
5 901
Благодарностей
6 376
Баллы
113
ку, пришло время работать с большим количеством строк, TXT файлы тут явно не прокатят как раньше )

короче говоря есть БД на 40гб в ней куча строк, надо взять каждую и сделать запрос по урлу в строке.
вопросы:
1. как лучше брать строки? есть также уникальные id в бд у каждой строки, если это важно
2. как НЕ взять туже строчку, которая уже в работе?
3. как лочить запросы к бд? гуглеж по форуму, дал инфу но я не разобрался в шарпах

моя логика
берем строку, обновляем статус строки на "в работе", делаем то что надо, в конце снова обновляем стату на "готово"

предложите свой вариант работы с бд, если он лучше и/или быстрее моего

прошу отписаться кто имел опыт.
спасибо
 

afk

Client
Регистрация
28.11.2016
Сообщения
99
Благодарностей
25
Баллы
18
Первый способ (с использованием файла с id):
1. Заранее делаем запрос "SELECT id FROM table;" (Сохраняем уникальные айди в файл допустим sqlId.txt . Если строк овермного - делаем несколько таких файлов.)
2. Далее по стандарту привязываем к списку файл с айдишками. Берём строку с id с удалением - делаем запрос SELECT * FROM table WHERE id = id_from_file.
3. Выполняем нужную нам работу.
При таком способе лок при взятии id будет реализован стандартным кубиком (в екшне Список->Взять строку).

Второй способ (без использования файла с id)
1. Добавляем в базу столбец status типа enum со значениями 'ready' , 'in_work', 'done', 'error'
2. Посредством C# делаем LOCK таблицы , SELECT, и UNLOCK .

Первый способ намного проще, но нужно играться с файлами, а также учитывать тот факт, что зенка может крашнуться в неподходящий момент и файл с входящими айдишками будет утерян.
Но можно также добавить "столбец status типа enum со значениями 'ready' , 'in_work', 'done', 'error'" и после каждой удачной отработке шаблона ставить status = 'done' , в случае ошибки status='error'.
И в случае, если зенка крашнется - можно сделать SELECT id FROM table WHERE status<>'done' и получить список id , которые ещё не отработали в вашем шаблоне или отработали с ошибкой и запустить их в работу заново.

От второго способа отказался, т.к. во время работы (конкретно в моём случае) нужно постоянно чекать базу вручную, а т.к. там делается лок - нужно стопать шаблон.
 

afk

Client
Регистрация
28.11.2016
Сообщения
99
Благодарностей
25
Баллы
18
UPD: если решите распаралелить работу на несколько зенок , которые работают с нескольких серверов то LOCK может существенно снизить КПД вашего шаблона.
 

luk911

Client
Регистрация
17.01.2013
Сообщения
1 542
Благодарностей
579
Баллы
113
Все еще проще, зачем таблицу то лочить не понятно... Дурные советы какие то...
Просто добавляешь поле lok.
Взял запись и тут же записал в это поле 1. Все остальные выбирают себе запись с фильтром по этому полю - в которых 0. Взял - залочил, закончил - разлочил.
Ну и так как не бывает - чтобы просто так все отработало - то отдельно напишешь скрипт - который будет проходить по всей таблице и снимать не снятые локи ...
 

Phoenix78

Client
Read only
Регистрация
06.11.2018
Сообщения
11 790
Благодарностей
5 678
Баллы
113
Все еще проще, зачем таблицу то лочить не понятно... Дурные советы какие то...
Просто добавляешь поле lok.
Взял запись и тут же записал в это поле 1. Все остальные выбирают себе запись с фильтром по этому полю - в которых 0. Взял - залочил, закончил - разлочил.
Ну и так как не бывает - чтобы просто так все отработало - то отдельно напишешь скрипт - который будет проходить по всей таблице и снимать не снятые локи ...
не будет так работать. будет брать дубли.
 
  • Спасибо
Реакции: Wide

luk911

Client
Регистрация
17.01.2013
Сообщения
1 542
Благодарностей
579
Баллы
113
не будет так работать. будет брать дубли.
Спасибо - кэп - не работает уже 2 года.

Не ну может у тебя там банковские транзакции с миллионом обращений к базе из 5 строк ... Тогда возможны накладки. А так этого больше чем достаточно.
 

Phoenix78

Client
Read only
Регистрация
06.11.2018
Сообщения
11 790
Благодарностей
5 678
Баллы
113

backoff

Client
Регистрация
20.04.2015
Сообщения
5 901
Благодарностей
6 376
Баллы
113
ничего не утверждаю, но мне тоже кажется что так не совсем логично, при одновременных 500 потоках, одна строка не будет успевать "залочится" или несколько потоков будут обрабатывать одну строчку с одинаковым результатом на выходе... в общем это ни есть lock в принципе...
и + это больше обращений к базе, что тоже не есть гуд

мне кажется самый простой варик это тот, что предложили с id... и локов нет, и обращений к бд минимум
 

luk911

Client
Регистрация
17.01.2013
Сообщения
1 542
Благодарностей
579
Баллы
113
ничего не утверждаю, но мне тоже кажется что так не совсем логично, при одновременных 500 потоках, одна строка не будет успевать "залочится" или несколько потоков будут обрабатывать одну строчку с одинаковым результатом на выходе... в общем это ни есть lock в принципе...
и + это больше обращений к базе, что тоже не есть гуд

мне кажется самый простой варик это то, что предложили с id... и локов нет, и обращений к бд минимум
У тя потоки на пост гетах ? строк на 500 потоков сколько ? Чтобы выбрать и обновить запись это милисекунды.
А запись на диск в файл ты считаешь быстрее будет делаться чем в памяти?
База в памяти работает, операции с диском скидываются накопитель. А ты с диском хочешь работать ... ну... На цвет и вкус ...
 

backoff

Client
Регистрация
20.04.2015
Сообщения
5 901
Благодарностей
6 376
Баллы
113
У тя потоки на пост гетах ?
да
строк на 500 потоков сколько ?
15кк
Чтобы выбрать и обновить запись это милисекунды.
1 select выполняется 0.015сек, остальные не замерял еще
А запись на диск в файл
не знаю, не замерял, но диск очень быстрый m2, надо тестить

ps \ у меня бд находится на тоже серваке, то есть и бд и текстовик на одном диске, думаю запись будет одинакова по скорости...
 

afk

Client
Регистрация
28.11.2016
Сообщения
99
Благодарностей
25
Баллы
18
ага, а идее с файлом куда как более интересная ... ну ну ... И лочить всю таблицу - замечательная идея :-)
Работаю с файлом таким образом ~ 4 года.
Да, немного костыль, да есть минусы, в моём случае самый удобный вариант работы.
 

luk911

Client
Регистрация
17.01.2013
Сообщения
1 542
Благодарностей
579
Баллы
113
Работаю с файлом таким образом ~ 4 года.
Да, немного костыль, да есть минусы, в моём случае самый удобный вариант работы.
да я ж не против, кто как хочит, так и ... Только не понятен ризон с файлами это делать, обновить запись добавив 1 к строке - в том же соединении с мускулем - будет быстрее, чем писать что либо в файл. С файлом операции записи будут последовательными, с базой нет.
Ну вообщем ладно. Всем хорошего настроения.
 

backoff

Client
Регистрация
20.04.2015
Сообщения
5 901
Благодарностей
6 376
Баллы
113
Первый способ (с использованием файла с id):
1. Заранее делаем запрос "SELECT id FROM table;" (Сохраняем уникальные айди в файл допустим sqlId.txt . Если строк овермного - делаем несколько таких файлов.)
2. Далее по стандарту привязываем к списку файл с айдишками. Берём строку с id с удалением - делаем запрос SELECT * FROM table WHERE id = id_from_file.
3. Выполняем нужную нам работу.
При таком способе лок при взятии id будет реализован стандартным кубиком (в екшне Список->Взять строку).
еще раз спасибо, все работает как часы

96811
 

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 711
Благодарностей
1 366
Баллы
113

Alexbrush

Client
Регистрация
20.11.2020
Сообщения
121
Благодарностей
93
Баллы
28
Тоже такой вопрос возник и с файлами реально хорошая идея.

Только Luk911 кажется не так понял всю логику с файлами. Туда не нужно постоянно что-то тянуть с базы и записывать - раз перед работой запустили процесс, вытащили все id в несколько файлов и после уже в зенке берём файлы по очереди, вяжем их к списку (без сохранения в файл) и оттуда построчно отрабатываем все id с удалением из списка, а не файла. В конце списка, как вариант можно добавить удаление файла, который был в основе списка разовым действием.

Т.е. файлы сами, их запись, перезапись не особо много участвуют в процессе.
 
  • Спасибо
Реакции: backoff

Alexbrush

Client
Регистрация
20.11.2020
Сообщения
121
Благодарностей
93
Баллы
28
imho, брать id в файл из БД и потом работать с этим файлом - это просто извращение какое-то ж) зачем тогда вообще БД здесь нужна?
При масштабе и большом количестве потоков будет много пересечений в запросах к базе. С временным хранением строк в файлах это сразу легко исключается.
 
  • Спасибо
Реакции: backoff

backoff

Client
Регистрация
20.04.2015
Сообщения
5 901
Благодарностей
6 376
Баллы
113
imho, брать id в файл из БД и потом работать с этим файлом - это просто извращение какое-то ж)
1. ну, "кто как хочет, так и дрочит" - никто не отменял :-)
2. для меня пока что это понятно как организовать
3. это работает с большой скоростью, на которую я расчитывал
зачем тогда вообще БД здесь нужна?
это чтобы 40гб файлов не было, плюс такое количество файлов явно замедлит работу
пока учусь с БД работать, можно и так начинать, тем более времени нет разбираться в локах и как они работают, надо уже сейчас результат

Только Luk911 кажется не так понял всю логику с файлами. Туда не нужно постоянно что-то тянуть с базы и записывать - раз перед работой запустили процесс, вытащили все id в несколько файлов и после уже в зенке берём файлы по очереди, вяжем их к списку (без сохранения в файл) и оттуда построчно отрабатываем все id с удалением из списка, а не файла. В конце списка, как вариант можно добавить удаление файла, который был в основе списка разовым действием.

Т.е. файлы сами, их запись, перезапись не особо много участвуют в процессе.
+1, очень понятно и удобно, и файлов просто крохи. збс идея
 

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 711
Благодарностей
1 366
Баллы
113
вся задача решается в пару строк кода с помощью UPDATE и LAST_INSERT_ID

C#:
db.query("UPDATE catalog SET status=LAST_INSERT_ID(id) WHERE status=0 LIMIT 1");
string id = db.getOne("SELECT LAST_INSERT_ID()"); // это id записи с которой дальше работаем
есть и более медленный вариант

генерим уникальное число (или строку)
UPDATE catalog SET status=сгенерированное_число LIMIT 1
далее получаем данные строки с которой работаем
SELECT * FROM catalog WHERE status=сгенерированное_число

хоть у вас 100500 потоков будет, но только один из них сможет заапдейтить конкретную строку, и никаких полных локов таблицы
 
Последнее редактирование:
  • Спасибо
Реакции: djaga

SERG454

Client
Регистрация
14.10.2021
Сообщения
137
Благодарностей
134
Баллы
43
Вопрос по БД, раз уж тут все собрались (звиняюсь за офтоп)
Плюс к работе с отдельным файлом ID - меньше запросов к базе одновременно ( то сначала за Id . потом за данными)
Сколько одновременных потоков /запросов может держать база /сервер ( например на Open Server) на "среднем" компе /сервере?
У меня "падает" , если больше 20 и( или 50 ...уже точно не помню) одновременных потоков ...шо делать?
Пока решил проблему так - в одном запросе к БД список действий отправляю, чтобы уменьшить общее коллво запросов к БД..а как грамотнее делается это?
Зы или отдельную тему создать?
 

backoff

Client
Регистрация
20.04.2015
Сообщения
5 901
Благодарностей
6 376
Баллы
113
меня "падает" , если больше 20 и( или 50 ...уже точно не помню) одновременных потоков ...шо делать?
Покарешил проблему так - в одном запросе к БД список действий отправляю, чтобы уменьшить общее коллво запросов к БД..а как грамотнее делается это?
я сам тут не особо эксперт по этой части, но! я организовал работу БД и обращений к ней как написано тут - https://zennolab.com/discussion/threads/pomogite-postroit-logiku-raboty-s-bd-i-ee-lokom-mnogopotok.106165/post-703168
обязательно в БД надо сделать auto_increment для первого столбца - id , это присвоение уникальности каждой строке, потом по ним делать работу, select/update и тп
у меня средний сервак, держит спокойно 600+ потоков, ничего не падает
возможно стоит оптимизировать шаблон, тут только тесты

вся задача решается в пару строк кода с помощью UPDATE и LAST_INSERT_ID
пасиб, покурю этот момент
 

WebBot

Client
Регистрация
04.04.2015
Сообщения
1 711
Благодарностей
1 366
Баллы
113
Вопрос по БД, раз уж тут все собрались (звиняюсь за офтоп)
Плюс к работе с отдельным файлом ID - меньше запросов к базе одновременно ( то сначала за Id . потом за данными)
Сколько одновременных потоков /запросов может держать база /сервер ( например на Open Server) на "среднем" компе /сервере?
У меня "падает" , если больше 20 и( или 50 ...уже точно не помню) одновременных потоков ...шо делать?
Пока решил проблему так - в одном запросе к БД список действий отправляю, чтобы уменьшить общее коллво запросов к БД..а как грамотнее делается это?
Зы или отдельную тему создать?
запрос запросу рознь
есть легие быстровыполняющиеся запросы, есть тяжелые долговыполяющиеся, есть использующие индексы, а есть не используеющие, есть те которые создают для отработки временные таблицы и файлы ... здесь нет никакого среднего по больнице, нужно рассматривать конкретный ПК и конкретные запросы и на таблицах с конкретным наполнением
 

infosimple

Client
Регистрация
01.01.2015
Сообщения
420
Благодарностей
61
Баллы
28
Работал с локом, если залочил и поток крашнулся, то все остальные сидят в ожидание. Постоянно юзаю вариант 1 от afk, через обычный txt.
 

one

Client
Регистрация
22.09.2015
Сообщения
6 785
Благодарностей
1 262
Баллы
113
2. как НЕ взять туже строчку, которая уже в работе?
1. в поле пишем время и смотрим по времени если больше Х пропускаем.
2. если в нужном поле 0 берем строку и пишем туда 1 (т.е. строка использовалась) и после окончания работы с базой возвращаем в это поле 0 для следующего раза.
 

backoff

Client
Регистрация
20.04.2015
Сообщения
5 901
Благодарностей
6 376
Баллы
113
1. в поле пишем время и смотрим по времени если больше Х пропускаем.
2+ потока могут изначально взять одну строчку, особенно когда шаблон стартуешь и одновременно запускается +-500 потоков
наелся я этих проверок в свое время, тут либо лок, либо удаление после взятия... id в файле, просто идеально
 

one

Client
Регистрация
22.09.2015
Сообщения
6 785
Благодарностей
1 262
Баллы
113
Я не испытывал проблем с этим в такой схеме. Правда давно уже было и деталей не помню. Не решение было такое и потоков было больше сотни.
 

Wide

Client
Регистрация
04.02.2013
Сообщения
944
Благодарностей
252
Баллы
63
Могу предложить рандомн кастомный. Но 500К строк 0,016 сек на запрос.
SQL:
SELECT product_id
FROM temp_id
WHERE product_id >= RAND() * (SELECT MAX(product_id) FROM temp_id)
ORDER BY product_id
LIMIT 1
Screenshot_290.pngScreenshot_291.pngScreenshot_297.png
 
Последнее редактирование:

Кто просматривает тему: (Всего: 1, Пользователи: 0, Гости: 1)