Ситуация тaкая, раз в минуту на разных серверах запускается cron. Который запускает php пишущий в одну и туже таблицу video_stats Server 1 Код (Text): UPDATE video_stats v,video_stats_tmp1 s SET v.views=v.views+s.views WHERE v.video_id = s.video_id; Server 2 Код (Text): UPDATE video_stats v,video_stats_tmp2 s SET v.views=v.views+s.views WHERE v.video_id = s.video_id; Mysql падает на : Deadlock found when trying to get lock; try restarting transaction Закрываю таблицу. Код (Text): $dbapp->query('LOCK TABLES video_stats v WRITE'); $dbapp->query(" UPDATE video_stats v,video_stats_tmp1 s SET v.views=v.views+s.views WHERE v.video_id = s.video_id"); $dbapp->query('COMMIT'); $dbapp->query('UNLOCK TABLES'); После LOCK-a , UPDATE вообще не срабатывает и висит закрытая таблица. Подскажите что вообще происходит ? Почему 2 запроса одновременно не могут писать в одну таблицу ? Что не правильного в использовании LOCK TABLES ? Спасибо.
Ну вот что делаю, может тут ошибка: Код (Text): $dbapp->query('LOCK TABLES video_stats v WRITE'); $dbapp->query(" UPDATE video_stats v,video_stats_tmp1 s SET v.views=v.views+s.views WHERE v.video_id = s.video_id"); $dbapp->query('COMMIT'); $dbapp->query('UNLOCK TABLES'); Вернее UPDATE срабатыват, только он до этого висит очень долго.
Именно апдейт? Или лок? Вот это Не должно возникать при локе одной единственной таблицы. Почему бы просто не сделать профайлинг системы?
Да именно UPDATE висит, как будто бы LOCK закрыл таблицу от всех и от своего UPDAT-a в том числе. Сейчас попробовал транзакции. Посмотрим будет ли падать. Код (Text): $dbapp->query('SET autocommit=0'); $dbapp->query('START TRANSACTION'); $dbapp->query(" UPDATE video_stats v,video_stats_tmp1 s SET v.views=v.views+s.views WHERE v.video_id = s.video_id"); $dbapp->query('COMMIT'); Это должно помочь ?
[злорадныйСмех] Муахахаха! Читать мануал нужно внимательно, а там написано, что лочить нужно aliases, которые используются в запросах. [/злорадныйСмех]
Ну так я и лочу alias LOCK TABLES video_stats v WRITE UPDATE video_stats v,video_stats_tmp1 s SET v.views=v.views+s.views WHERE v.video_id = s.video_id Или я что то не так понял ?
evgeny12000 А s кто будет лочить? Я же говорю, читаем мануал внимательно С этими локами там куча нюансов - сделать то, сделать это, сё низя, это низя, а эту хрень вообще не мечтайте.
Вроде бы делаю правильный запрос. Код (Text): <?php $link = mysqli_connect(LBHOST,LBUSER,LBPASS, LBNAME); mysqli_query($link, "LOCK TABLES stats WRITE"); mysqli_query($link, "update stats set status=444 where id=8312"); mysqli_query($link, "UNLOCK TABLES"); mysqli_close($link); ?> Запускаю php , иногда срабатывает быстро, а иногда зависает и висит пол минуты. В случаях когда висит, в show processlist пишет: Locked update stats set status=444 where id=8312 Объясните пожалуйста что происходит ?
Так вот делаю : Код (Text): $dbapp->query('SET autocommit=0'); $dbapp->query('START TRANSACTION'); $dbapp->query(" UPDATE video_stats v,video_stats_tmp1 s SET v.views=v.views+s.views WHERE v.video_id = s.video_id"); $dbapp->query('COMMIT'); Не помогает... Все равно периодически получаю: Deadlock found when trying to get lock; try restarting transaction
Жесть то какая. Ну посмотри же ты данные свои. В чем разница между теми запросами, которые вызывают deadlock и теми что не вызывают. [sql]SELECT video_stats CROSS JOIN video_stats_tmpl ON video_stats.video_id = video_stats_tmpl.video_id [/sql] насчет CROSS не уверен, может без него надо, я точно не помню. По итогу попробуй заменить свой UPDATE на SELECT FOR UPDATE
цитата: Deadlock'и, т.е. тупиковая ситуация одновременных процессов (потоков) которые нуждаются в одних и тех же или зависимых друг от друга данных часто возникают в программировании. InnoDB не исключение. Например если идут две транзакции и каждая хочет изменить ресурсы (строки/диапазон строк) которые сейчас заблокированы. Получается что ни одна транзакция не может закончится. В таких ситуациях InnoDB вынуждена откатить одну из транзакций и выдать ошибку все, что надо сделать - ПОВТОРИТЬ запрос, т.е. словить ошибку. посмотреть номер и если что - повторить запрос.
Офигеть просто ... Получается что в Innodb одновременно делать действия на много записей вообще нельзя ? Неужели у меня такая нестандартная ситуация ? Просто нужно закрыть таблицу, и все процессы чтоб в очередь стали. 440Hz - То что вы пишите это логично, но нет ли какого то более практичного решения ? Если работать с откатами транзакций, это получается что на каждый запрос в случае падения, нужно делать SLEEP() на какойто количество секунд а потом повторять транзакцию ? То есть loop который запихивает транзакции ?
нет, но если возникает таки ситуации (у меня возникали при ооооочень больших нагрузках, не знаю уж почему у вас они), то все просто: делается ->query($sql); смотриться ошибка. если надо повторить транзакцию, то она СРАЗУ же повторяется, т.е. $sql летит опять. без задержек. я обернул ->query() в свою обертку и там все словил.