За последние 24 часа нас посетили 19214 программистов и 1621 робот. Сейчас ищут 1058 программистов ...

Deadlock found when trying to get lock

Тема в разделе "MySQL", создана пользователем evgeny12000, 22 фев 2010.

  1. evgeny12000

    evgeny12000 Активный пользователь

    С нами с:
    22 фев 2010
    Сообщения:
    22
    Симпатии:
    0
    Ситуация тaкая, раз в минуту на разных серверах запускается cron.
    Который запускает php пишущий в одну и туже таблицу video_stats

    Server 1
    Код (Text):
    1.    UPDATE video_stats v,video_stats_tmp1 s
    2.         SET v.views=v.views+s.views
    3.         WHERE v.video_id = s.video_id;
    Server 2
    Код (Text):
    1.    UPDATE video_stats v,video_stats_tmp2 s
    2.         SET v.views=v.views+s.views
    3.         WHERE v.video_id = s.video_id;
    Mysql падает на : Deadlock found when trying to get lock; try restarting transaction

    Закрываю таблицу.

    Код (Text):
    1.  
    2. $dbapp->query('LOCK TABLES video_stats v WRITE');
    3. $dbapp->query("
    4.         UPDATE video_stats v,video_stats_tmp1 s
    5.         SET v.views=v.views+s.views
    6.         WHERE v.video_id = s.video_id");
    7. $dbapp->query('COMMIT');
    8. $dbapp->query('UNLOCK TABLES');
    После LOCK-a , UPDATE вообще не срабатывает и висит закрытая таблица.

    Подскажите что вообще происходит ?
    Почему 2 запроса одновременно не могут писать в одну таблицу ?
    Что не правильного в использовании LOCK TABLES ?
    Спасибо.
     
  2. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Ошибки?
     
  3. evgeny12000

    evgeny12000 Активный пользователь

    С нами с:
    22 фев 2010
    Сообщения:
    22
    Симпатии:
    0
    Ошибки нет.
    Запрос висит в состоянии LOCKED.
     
  4. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Так не бывает. Лочишь только одну эту таблицу?
     
  5. evgeny12000

    evgeny12000 Активный пользователь

    С нами с:
    22 фев 2010
    Сообщения:
    22
    Симпатии:
    0
    Ну вот что делаю, может тут ошибка:
    Код (Text):
    1.  
    2. $dbapp->query('LOCK TABLES video_stats v WRITE');
    3. $dbapp->query("
    4.        UPDATE video_stats v,video_stats_tmp1 s
    5.        SET v.views=v.views+s.views
    6.        WHERE v.video_id = s.video_id");
    7. $dbapp->query('COMMIT');
    8. $dbapp->query('UNLOCK TABLES');
    Вернее UPDATE срабатыват, только он до этого висит очень долго.
     
  6. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Именно апдейт? Или лок?

    Вот это
    Не должно возникать при локе одной единственной таблицы.

    Почему бы просто не сделать профайлинг системы?
     
  7. evgeny12000

    evgeny12000 Активный пользователь

    С нами с:
    22 фев 2010
    Сообщения:
    22
    Симпатии:
    0
    Да именно UPDATE висит, как будто бы LOCK закрыл таблицу от всех и от своего UPDAT-a в том числе.

    Сейчас попробовал транзакции. Посмотрим будет ли падать.

    Код (Text):
    1. $dbapp->query('SET autocommit=0');
    2. $dbapp->query('START TRANSACTION');
    3. $dbapp->query("
    4.        UPDATE video_stats v,video_stats_tmp1 s
    5.        SET v.views=v.views+s.views
    6.        WHERE v.video_id = s.video_id");
    7. $dbapp->query('COMMIT');
    Это должно помочь ?
     
  8. Костян

    Костян Активный пользователь

    С нами с:
    12 ноя 2009
    Сообщения:
    1.724
    Симпатии:
    1
    Адрес:
    адуктО
    нет....
    А без LOCK TABLES video_stats v WRITE апдейт долго выполняется?
     
  9. evgeny12000

    evgeny12000 Активный пользователь

    С нами с:
    22 фев 2010
    Сообщения:
    22
    Симпатии:
    0
    Нет, 2 секунды.
     
  10. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    [злорадныйСмех]
    Муахахаха!

    Читать мануал нужно внимательно, а там написано, что лочить нужно aliases, которые используются в запросах.
    [/злорадныйСмех]
     
  11. evgeny12000

    evgeny12000 Активный пользователь

    С нами с:
    22 фев 2010
    Сообщения:
    22
    Симпатии:
    0
    Ну так я и лочу 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

    Или я что то не так понял ?
     
  12. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    evgeny12000
    А s кто будет лочить? Я же говорю, читаем мануал внимательно :) С этими локами там куча нюансов - сделать то, сделать это, сё низя, это низя, а эту хрень вообще не мечтайте.
     
  13. evgeny12000

    evgeny12000 Активный пользователь

    С нами с:
    22 фев 2010
    Сообщения:
    22
    Симпатии:
    0
    Вроде бы делаю правильный запрос.
    Код (Text):
    1.  
    2. <?php
    3. $link = mysqli_connect(LBHOST,LBUSER,LBPASS, LBNAME);
    4. mysqli_query($link, "LOCK TABLES stats WRITE");
    5. mysqli_query($link, "update stats set status=444 where id=8312");
    6. mysqli_query($link, "UNLOCK TABLES");
    7. mysqli_close($link);
    8. ?>
    Запускаю php , иногда срабатывает быстро, а иногда зависает и висит пол минуты.
    В случаях когда висит, в show processlist пишет:
    Locked update stats set status=444 where id=8312

    Объясните пожалуйста что происходит ?
     
  14. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    база myisam или Inno ?
     
  15. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    а зачем лочишь вообще? а как на счет транзакций?
     
  16. evgeny12000

    evgeny12000 Активный пользователь

    С нами с:
    22 фев 2010
    Сообщения:
    22
    Симпатии:
    0
  17. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    я бы при инно вообще не лочил. там внутренний лок как раз на уровне строки а не таблицы.
     
  18. evgeny12000

    evgeny12000 Активный пользователь

    С нами с:
    22 фев 2010
    Сообщения:
    22
    Симпатии:
    0
    Так вот делаю :
    Код (Text):
    1. $dbapp->query('SET autocommit=0');
    2. $dbapp->query('START TRANSACTION');  
    3. $dbapp->query("
    4.        UPDATE video_stats v,video_stats_tmp1 s
    5.        SET v.views=v.views+s.views
    6.        WHERE v.video_id = s.video_id");
    7. $dbapp->query('COMMIT');
    Не помогает... Все равно периодически получаю: Deadlock found when trying to get lock; try restarting transaction
     
  19. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Жесть то какая.
    Ну посмотри же ты данные свои. В чем разница между теми запросами, которые вызывают 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
     
  20. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    цитата: Deadlock'и, т.е. тупиковая ситуация одновременных процессов (потоков) которые нуждаются в одних и тех же или зависимых друг от друга данных часто возникают в программировании. InnoDB не исключение. Например если идут две транзакции и каждая хочет изменить ресурсы (строки/диапазон строк) которые сейчас заблокированы. Получается что ни одна транзакция не может закончится.

    В таких ситуациях InnoDB вынуждена откатить одну из транзакций и выдать ошибку



    все, что надо сделать - ПОВТОРИТЬ запрос, т.е. словить ошибку. посмотреть номер и если что - повторить запрос.
     
  21. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    о чем и сказано...
     
  22. evgeny12000

    evgeny12000 Активный пользователь

    С нами с:
    22 фев 2010
    Сообщения:
    22
    Симпатии:
    0
    Офигеть просто ...
    Получается что в Innodb одновременно делать действия на много записей вообще нельзя ?
    Неужели у меня такая нестандартная ситуация ? Просто нужно закрыть таблицу, и все процессы чтоб в очередь стали.

    440Hz - То что вы пишите это логично, но нет ли какого то более практичного решения ?
    Если работать с откатами транзакций, это получается что на каждый запрос в случае падения,
    нужно делать SLEEP() на какойто количество секунд а потом повторять транзакцию ? То есть loop который запихивает транзакции ?
     
  23. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    можно. Нельзя одновременно записать во все записи, когда кто-то другой в них уже пишет.
     
  24. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    нет, но если возникает таки ситуации (у меня возникали при ооооочень больших нагрузках, не знаю уж почему у вас они), то все просто:


    делается ->query($sql);
    смотриться ошибка.
    если надо повторить транзакцию, то она СРАЗУ же повторяется, т.е. $sql летит опять. без задержек.

    я обернул ->query() в свою обертку и там все словил.
     
  25. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    чече нужно?