Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Базы Данных > Обработка базы в несколько потоков


Автор: Ibragim 17.5.2007, 22:51
Вечер добрый.
Есть следующая ситуация. 
Данные хранятся в таблице MySQL, положим, с тремя полями id, name, value
В таблице name уже присвоены, а рассчтать и заполнить значения value и стоит задача.

Имея один "обработчик", мы делаем так
1. Выбираем очередную необработанню запись: SELECT id, name FROM `my_table` WHERE value="" LIMIT 1
2. Исходя из name рассчитываем значение value
3. Сохраняем значение value: UPDATE `my_table` SET value="<рассчитанное value>" WHERE id="<соотв. id>"

Но задача стоит сделать много обработчиков, то есть много копий скрипта, обновляющих эти значение value параллельно.
Счас реализовано вот так:
1. UPDATE `my_table` SET value="<уникальное сгенерированное значение>" WHERE value="" LIMIT 1
2. SELECT id, name FROM `my_table` WHERE value="<это сгенерированное значение>" 
3. Рассчет значения value
4. Сохранение UPDATE `my_table` SET value="<рассчитанное value>" WHERE id="<соотв. id>"

Есть ли более оптимальный способ "сказать" mysql что данная запись уже обрабатывается другой копией скрипта, и надо выбрать следующую? Как обычно поступают в таких случаях?

Автор: -=Ustas=- 18.5.2007, 14:20
Делай промежуточную табличку очередей, в которую ты сначала считаваешь записи, а затем уже запускаешь сколько угодно скриптов, которые из этой таблички выбирают верхние записи, и следовательно сразу же свою запись грохают, хотя может при выборе верхней записи каждым экземпляром скрипта нужно будет еще лочить таблицу.

Автор: WolfON 18.5.2007, 17:17
А расчет значения нельзя осуществить в рамках синтаксиса SQL-запросов (даже если с промежуточными таблицами) ?

Тут все все-таки упирается в скорость выполнения запросов сервером, а не в том, как часто их может посылать скрипт (если расчеты не сложные, выигрыш от многопоточности будет мизерным, да и не обязательно, что будет)


Еще можно почитать вот это:
http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html 

Автор: Ibragim 18.5.2007, 21:50
2-=Ustas=-: спасибо за совет, только практически я ео реализовать не представляю как. Таблица `my_table` достаточно велика, делать ее КОПИЮ чтобы из нее делетить не представляется возможным. А если делать маленькую промежуточную, то получается еще один скрипт, который "наполняет" по мере обсчитывания эту промежуточную следующими значениями из большой. Наверно будет быстрее (меньше запросов к большой таблице), но уж очень "витиевато" получается, буду думать.
2WolfON: Я однозначно уверен что нужно много потоков ввиду специфики задачи. Рассчет - понятие условное, включает в себя закачивание из интернета, ожидание от медленных серверов и так далее.

PS Да, а можно как-то залочить именно записть и сказать MySQL "SELECT name FROM `mytable` WHERE value="" AND <ЗАПИСЬ_НЕ_ЗАЛОЧЕНА> LIMIT 1" ?

Автор: sTa1kEr 24.5.2007, 19:47
Ibragim, 
Цитата(Ibragim @  18.5.2007,  21:50 Найти цитируемый пост)
Таблица `my_table` достаточно велика, делать ее КОПИЮ чтобы из нее делетить не представляется возможным.

В таком случае можно создать временную таблицу в памяти и записывать в нее id обрабатываемых в данный момент строк. А при выборке новых строк для обработки делать LEFT JOIN на нее с условием на неравенство id-шников.

Если же value заполняется только один раз для каждой строки, то еще оптимальней записывать только один id, а дальше делать выборку большему значению.

Цитата(Ibragim @  18.5.2007,  21:50 Найти цитируемый пост)
PS Да, а можно как-то залочить именно записть и сказать MySQL "SELECT name FROM `mytable` WHERE value="" AND <ЗАПИСЬ_НЕ_ЗАЛОЧЕНА> LIMIT 1" ?

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

Автор: teroni 24.5.2007, 23:13
Я обычно в таких случаях делаю текстовый файл, в котором изначально записан 0. При запуске каждая копия обработчика считывает это значение, и записывает в файл на единицу большее. Таким образом, каждый работающий скрипт-обрабочик имеет свой уникальный ID и в соответствии с этим уже делает свою работу.

Автор: Ibragim 15.6.2007, 20:30
Если еще кому-то будет интересно напишу как в конце-концов реализовал.
Сделал еще одну таблицу с одним полем и одной записью

Каждый обработчик
- лочит эту вспомог. таблицу
- читает из вспомогательной таблицы значение ее единственной записи, скажем my_var
- считывает из основной следующее значение так: WHERE primary_key > my_var ORDER BY primary_key
- записывает во вспомог. таблицу PRIMARY key текущего значения
- разлочивает вспомог. таблицу.

То есть фактически в вспомогательной таблице находится переменная, значение которой равно "ID последней ВЗЯТОЙ НА ОБРАБОТКУ записи основной таблицы". 

PS ORDER BY primary_key  не тормозит обработку ни в коей мере.

Вот, может кому пригодится.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)