Требуется помощь (innoDB, блокировка)

12
Пуховой
На сайте с 17.11.2007
Offline
154
1115

Доброго времени суток!

Есть таблица (name | abal) innoDB, где abal - баланс пользователя. Нужно обновлять балансы пользователей потокобезопасно (за 1 сек. нужно 100-150 раз изменить значение abal в меньшую сторону, из разных копий запущенного скрипта).

Правильно ли:

SELECT * FROM `user` WHERE `name` = '$name' LIMIT 1 FOR UPDATE;

... $abal = $abal - 0.001;
UPDATE `owls`.`user` SET `abal` = '$abal' WHERE `user`.`name` = '$name' LIMIT 1;

Будет ли заблокирована используемая строчка в таблице до её обновления?

Заранее спасибо за ответы.

С уважением.

N
На сайте с 06.05.2007
Offline
419
#1

должна быть заблокирована. если вы не забыли в скрипте отключить autocommit.

по этой же причине у вас возможно и не получится достичь высокой конкурентности и "за 1 сек. 100-150 раз изменить значение abal в меньшую сторону".

Кнопка вызова админа ()
Пуховой
На сайте с 17.11.2007
Offline
154
#2

Но если применить SET AUTOCOMMIT=0:

SET AUTOCOMMIT=0


SELECT * FROM `user` WHERE `name` = '$name' LIMIT 1 FOR UPDATE;
... $abal = $abal - 0.001;
UPDATE `owls`.`user` SET `abal` = '$abal' WHERE `user`.`name` = '$name' LIMIT 1;

COMMIT

По сути дела, повышения производительности не стоит ожидать?

S
На сайте с 24.10.2009
Offline
14
#3

Не рассматривали следующий вариант?

UPDATE `owls`.`user` SET `abal` = `abal` - 0.01 WHERE `user`.`name` = '$name' LIMIT 1; 

Так будет быстрее работать при большом количестве потоков (потоки будут блокироваться на меньшее время).

Программирование сложных проектов; http://shagabutdinov.com (http://shagabutdinov.com)
Пуховой
На сайте с 17.11.2007
Offline
154
#4

Shagabutdinov, к сожалению, очень плохо разбираюсь в теме. Да что там - вообще мало чего понимаю, пытаюсь делать как обычно, интуитивно (опыт есть в программировании под форточки лишь).

N
На сайте с 06.05.2007
Offline
419
#5

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

вы не преувеличиваете ? разве возможна ситуация когда у одного и того же пользователя за одну секунду списывается по 1 копейке 150 раз?

150 списаний у разных пользователей обычно не вызовут большой проблемы. за исключением случая неправильно расставленных индексов.

Пуховой
На сайте с 17.11.2007
Offline
154
#6

Попробую пояснить.

У пользователя на сервере установлено многопоточное ПО, которое делает до пятисот запросов в секунду на мой сервер. Грубо говоря, посылает некоторую информацию, которую мой сервер должен обработать и выдать результат, вместе с тем снять со счета пользователя, грубо говоря, копейку. ПО крайне специфично - отправлять данные на обработку последовательно, порционно никак не получится - каждый из потоков хаотично делает обращения на мой сервер.

Как можно повысить быстродействие в этом случае, как считаете?

Пуховой добавил 09.08.2011 в 09:47

Речь о списании именно у конкретного пользователя.

S
На сайте с 24.10.2009
Offline
14
#7

Пуховой, смысл в том, что, в общем случае, запись:


$abal = $db->fetchOne( 'SELECT abal FROM `user` WHERE `name` = "' . $name. '" LIMIT 1 FOR UPDATE' );
$abal = $abal - 0.001;
$db->query( 'UPDATE `owls`.`user` SET `abal` = "' . $abal . '" WHERE `user`.`name` = "' . $name. '" LIMIT 1' );

Эквивалентна записи:


$db->query( 'UPDATE `owls`.`user` SET `abal` = `abal` - 0.001 WHERE `user`.`name` = "' . $name. '" LIMIT 1' );

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

Shagabutdinov добавил 09.08.2011 в 10:14

Почему-то сразу подумалось о кэширующем буфере, который накапливает изменения, а потом выдаёт один sql-запрос. То есть, приложение сохраняет изменения где-то в быстрой памяти (вроде memcache), а потом списывает не по одной копейке, а сразу по рублю. Это бы сняло нагрузку с БД.

Если говорить о снятии нагрузки с сервера в целом, то я бы посоветовал следующее:

1. Системы кэширования оп-кода (вроде APC)

2. Более быстрый сервер (например, nginx)

3. Кэширование

4. Оптимизация алгоритов

5. Переписывание узких мест системы на что-нибудь более быстрое, чем php (до этого пункта редко доходят)

Вообще, про оптимизацию приложений много написано, нужно просто поискать :)

Пуховой
На сайте с 17.11.2007
Offline
154
#8

Shagabutdinov, вот думаю, где взять такую БД, чтобы работала в оперативной памяти, а изменения кидала на диск раз в минуту, скажем, и то в виде защиты от сбоя. Вместе с тем чтобы были возможности синхронизации более интересные, нежели блокирование целой таблицы.

Пока же:

- с запросом все ясно

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

SG
На сайте с 22.04.2008
Offline
32
SAG
#9
Пуховой:
Shagabutdinov, вот думаю, где взять такую БД, чтобы работала в оперативной памяти, а изменения кидала на диск раз в минуту, скажем, и то в виде защиты от сбоя.

http://dev.mysql.com/doc/refman/5.0/en/memory-storage-engine.html ?

Мemcached? APC? Учтите, что блокирование в них изначально не предусмотрено.

Портфолио (http://beastman.me). Верстаю (/ru/forum/228498). Програмлю (/ru/forum/348359). Последние отзывы (/ru/forum/470865). Контакты: ICQ: 31377144пять;E-mail: andrschwartz<собако>gmail.com
S
На сайте с 24.10.2009
Offline
14
#10

Если вы решили сменить БД, то могу посоветовать смотреть в сторону MSSql или Oracle (в Oracle точно есть хранение в памяти + журналирование, а также работа с несколькими дисками), но, ничего конкретного сказать не могу, так как сам мало работал с этими БД. Да и стоят они дороговато для рядовых проектов :) И ещё: следует предупредить, что в рабочих проектах (особенно под такой нагрузкой) менять БД очень сложно и чревато большими проблемами, я бы, на вашем месте, продолжал работать с той БД, которая есть, используя дополнительные средства.

SAG, в memcached есть атомарные операции (сложить, вычесть), этого достаточно для снятия опасности записи одной и той же ячейки несколькими потоками одновременно (при правильном программировании, разумеется). Про наличие атомарных операций в APC не знаю.

12

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий