Комментарии 42
Приветствую. Хорошая задача подобрана под ответ. Имхо, лучше оформить "##SELECT * FROM table FOR UPDATE##" без решеток - потребовалось несколько секунд чтобы разобраться, что два начальных не часть SELECT.
+1
А не могли бы Вы рассказать, хотя бы в общих чертах, что за проект?
0
Часть ERP системы: конструктор «событий», то бишь администратор портала может сам собирать сложные логические «блоки», которые прорадабываются в случае разные событий. Банальный пример — пользователь системы создаёт в CRM модуле новый контакт с набором характеристик. Админ в «конструкторе событий» описывает логику, где проверяются харакретистики и выполняются разные действия, например: спросить подтверждения у менеджера группы, отправить мейл тому-то, присобачить контакт к такой-то компании, создать где-то какую-то линию действий для этого контакта и тд и тп. В итоге получаются довольно сложные схемы. Если учесть что «событий» в даже очень простой ERP системе может генерироваться сотни в минуту, задача по отработке логики оных нетривиальна. Но как показывает практика — нет невозможных задачь ;)
0
Последний запрос, в котором и должен быть волшебный FOR UPDATE, его собственно не содержит :)
0
Салют clops =) а innodDB тюнили как Петя Зайцев учит ???
ну там нереальный InnoDB_pool_size и т.п.???
ну там нереальный InnoDB_pool_size и т.п.???
0
с самой инной проблем не ощущаем, кстати... подкрутили конечно несколько болтиков как в мане рекомендуют, но особых танцев с бубном пока не было )
0
execute_at (datetime), executed_at (datetime)
эх, сдается мне, уже было или еще будет проведен не один час в поисках бага. Тем более, что буквы E и D находятся рядом ;)
По теме:
а у вас INSERT в таблицу "queue" не лочится, пока вы пережевываете записи, полученные SELECT ... FOR UPDATE?
У нас вот стояла похожая задача, мы сделали так (местами синтаксис PHP), грубый пример:
0) генерируем какой-нибудь уникальный по времени и по демону $pid;
$pid = $server_uid . ":" . microtime(true);
1) и подминаем под него интересующие нас записи:
db_query("UPDATE tbl SET process_id='$pid', in_process=1 WHERE event_id='$eid'");
2) потом не спеша эти записи обрабатываем:
db_query("BEGIN");
$result = db_query("SELECT * FROM tbl WHERE process_id='$pid' AND in_process=1");
while($row=db_fetch($result){db_query("UPDATE tbl SET value='blablabla' WHERE id='$row->id';");}
db_query("COMMIT;");
эх, сдается мне, уже было или еще будет проведен не один час в поисках бага. Тем более, что буквы E и D находятся рядом ;)
По теме:
а у вас INSERT в таблицу "queue" не лочится, пока вы пережевываете записи, полученные SELECT ... FOR UPDATE?
У нас вот стояла похожая задача, мы сделали так (местами синтаксис PHP), грубый пример:
0) генерируем какой-нибудь уникальный по времени и по демону $pid;
$pid = $server_uid . ":" . microtime(true);
1) и подминаем под него интересующие нас записи:
db_query("UPDATE tbl SET process_id='$pid', in_process=1 WHERE event_id='$eid'");
2) потом не спеша эти записи обрабатываем:
db_query("BEGIN");
$result = db_query("SELECT * FROM tbl WHERE process_id='$pid' AND in_process=1");
while($row=db_fetch($result){db_query("UPDATE tbl SET value='blablabla' WHERE id='$row->id';");}
db_query("COMMIT;");
0
полность согласен:
1 - занимаем записи
1.а - проверяем, сколько строк затронул апдейт.
2. - если затронутые ряды есть - не спеша эти записи обрабатываем:
неплохобы еще и организовать демон, которые периодически проверяет - а есть ли записи, залоченные за процесс, но выполняющиеся долго - процесс то мог и вывалиться во время работы.
1 - занимаем записи
1.а - проверяем, сколько строк затронул апдейт.
2. - если затронутые ряды есть - не спеша эти записи обрабатываем:
неплохобы еще и организовать демон, которые периодически проверяет - а есть ли записи, залоченные за процесс, но выполняющиеся долго - процесс то мог и вывалиться во время работы.
0
А всё — элементарно
Столько буков ради того, чтобы сказать миру, что Вы наконец-то удосужились прочесть мануал?
0
Мать моя женщина! Мускулистые парни - это все делал фокспро на автомате - достаточно было выставить один флаг
0
Полезно в любом случае.
0
Спасибо! Как раз на этой неделе появилась задача перелопачивать большую очередь заданий десятками демонов - тоже никак не мог придумать как метить взятые на обработку...
Чума нашего времени. Айтишные знания очень глубокие. Есть нетривиальная задача и кто-то придумал ей красивое решение, назовем его "for update", об этом решении знает 1 из 100. 49 спецов потратят несколько часов на чтение мануалов и гугление с негарантированным результатом, еще 50 будут три дня писать incredible machine делающую аналог "for update". И только один готов за полсекунды ответить - "юзайте "for update". Вопрос - как за кратчайшее время найти этого одного?
Чума нашего времени. Айтишные знания очень глубокие. Есть нетривиальная задача и кто-то придумал ей красивое решение, назовем его "for update", об этом решении знает 1 из 100. 49 спецов потратят несколько часов на чтение мануалов и гугление с негарантированным результатом, еще 50 будут три дня писать incredible machine делающую аналог "for update". И только один готов за полсекунды ответить - "юзайте "for update". Вопрос - как за кратчайшее время найти этого одного?
+3
Найдите один раз одного знакомого, который прошёл нормальный курс подготовки по базам данных, только и всего - тот, где среди прочего рассматриваются транзакции, блокировки и способы их реализации в основных СУБД - и использует эти знания на деле. Если совсем лень - запостите в разделе "Проектирование" на форуме SQL.ru.
Если вы сами разработчик - то лучше пройти такой курс самостоятельно.
Если вы сами разработчик - то лучше пройти такой курс самостоятельно.
0
Не мысли плоско... Таких задач сотни и направлений в айти - не меньше. Искать сотни супергуру себе в знакомые - жизни не хватит.
0
Реализация транзакций и блокировок в каждой СУБД своя поэтому в любом случае потребуется или время на поиск рещения в документации или на поиск человек который уже работал с данной СУБД.
0
Кроме того, это решение не является красивым, потому как:
1) Да, изолируется обновление строк между процессами.
2) Но тот процесс I, который попал на чтение ещё не обновлённой, но заблокированной на запись выборки процессом II, ждёт окончания обновления I-м.
Просто поскольку обновление похоже занимает меньше времени, чем обработка, то это даёт выигрыш по сравнению с блокировкой записей на время обработки (полная транзакция).
1) Да, изолируется обновление строк между процессами.
2) Но тот процесс I, который попал на чтение ещё не обновлённой, но заблокированной на запись выборки процессом II, ждёт окончания обновления I-м.
Просто поскольку обновление похоже занимает меньше времени, чем обработка, то это даёт выигрыш по сравнению с блокировкой записей на время обработки (полная транзакция).
0
увы, решение, конечно, не блещет, тут вы — правы! да, вы правы — выигрышь в производительности тут исключительно в том, что обновение занимает меньше времени чем обработка :)
однако а) с своей задачей справляется великолепно б) было введено в действие менее чем за сутки (это включая тесты на производительность!)
однако а) с своей задачей справляется великолепно б) было введено в действие менее чем за сутки (это включая тесты на производительность!)
0
В Вашем примере где в конце LIMIT 1 FOR UPDATE не будет использоваться построчная блокировка.
Если пустить в другом коннекте такой же запрос до того как в первом сказан COMMIT будет стандартное ожидание освобождения лока.
Если уж дошли в мануале до селекта, посмотрите в каких случаях происходит построчная блокировка.
Если пустить в другом коннекте такой же запрос до того как в первом сказан COMMIT будет стандартное ожидание освобождения лока.
Если уж дошли в мануале до селекта, посмотрите в каких случаях происходит построчная блокировка.
0
Как это "Трансакции не дают должного результата"?! Как раз классическое решение этой задачи - в обертывании select и update в одну транзакцию. Другой вопрос, что mysql... не очень транзакционная СУБД ;) Поэтому ей такие подсказки необходимы, чтобы нормально работать.
0
Не поможет обертывание в транзакцию, если SELECT в ней не for update.
Две транзакции могут сделать SELECT до того, как в первой из них пройдет commit.
Две транзакции могут сделать SELECT до того, как в первой из них пройдет commit.
0
НЛО прилетело и опубликовало эту надпись здесь
А я не заморачивался по поводу FOR UPDATE, так как на моем мыскале нет InnoDB...
Я взял следующую выборку:
SELECT * FROM tbl WHERE id%N=n LIMIT скока надо;
где N - количество демонов, обслуживающих очередь,
n - номер демона (присваивается при старте демона и не повторяется у остальных демонов)
В результате не нужно рукоблудие с локами. Правда появилось рукоблудие с демонами, но оно решается гораздо легче.
И рациональное предложение - а не завести ли Вам на каждой физической машине по очереди (MySQL таблица) и паре..тройке демонов, работающих с этой локальной очередью ?
Я взял следующую выборку:
SELECT * FROM tbl WHERE id%N=n LIMIT скока надо;
где N - количество демонов, обслуживающих очередь,
n - номер демона (присваивается при старте демона и не повторяется у остальных демонов)
В результате не нужно рукоблудие с локами. Правда появилось рукоблудие с демонами, но оно решается гораздо легче.
И рациональное предложение - а не завести ли Вам на каждой физической машине по очереди (MySQL таблица) и паре..тройке демонов, работающих с этой локальной очередью ?
0
Тоже иногда использую такое распараллеливание, только как правило не по id. Минусы для автора очевидны - возможно такое построение задач, при котором большая часть нагузки уйдёт в один из потоков.
+1
демонов сложно менеджить когда их много. более того, они «поднимаются» автоматически при необходимости!
0
а в SELECT вашем индексы-то не используются. и производительность сильно падает.
0
Мега-прокачанный проект открывает для себя транзакции. Смешно
0
простое применение транзакций в данном случае проблемы не решает, смешно, что не прочитали внимательно
0
FOR UPDATE - это частный случай блокировки, а блокировка - это и есть одна из изюминок транзакций :)
0
А по-моему смешно, что Вы утверждаете, что FOR UPDATE помогает демонам "просто не видеть ряд". Ибо это бред. И, как я уже до этого написал, всё равно вышеприведённые запросы НЕ ПОЗВОЛЯЮТ распараллеливать задачи!
0
К этому надо очень аккуратно подходить. Просчитывать все до мельчайших деталей. Делать нагрузочные тестирования. Мы уже с этим напоролись, такая блокировка создалась на Oracle от SELECT`a FOR UPDATE. Бизнес стоял.
0
Зарегистрируйтесь на Хабре , чтобы оставить комментарий
Row Locking во время выборки в MySQL