2011-01-24 27 views
3

Railsのバージョン:2.3.8ActiveRecordの「MySQLの::エラー:超過ロック待機タイムアウト」明白なロックと

多くの回日thoughout、私のアプリケーションは、一見ランダムで対応するエントリと500エラーが返されます生産履歴:MySQLのスロークエリログを点検

ActiveRecord::StatementInvalid (Mysql::Error: Lock wait timeout exceeded; try restarting transaction: INSERT INTO `forum_posts` (`forum_topic_id`, `created_at`, `body`, `ancestry`, `updated_at`, `quote_limit`, `user_id`, `ancestry_depth`, `quote_root`) VALUES(1224783, '2011-01-24 19:18:38', 'Post body', '1285704', '2011-01-24 19:18:38', 1, 57931, 1, 1)) 

は、このエントリを示していますRailsのログによると

# Time: 110124 11:19:29 
# [email protected]: db_user[db_user] @ localhost [] 
# Query_time: 51 Lock_time: 0 Rows_sent: 0 Rows_examined: 0 
SET insert_id=0; 
INSERT INTO `forum_posts` (`forum_topic_id`, `created_at`, `body`, `ancestry`, `updated_at`, `quote_limit`, `user_id`, `ancestry_depth`, `quote_root`) VALUES(1224783, '2011-01-24 19:18:38', 'Post body', '1285704', '2011-01-24 19:18:38', 1, 57931, 1, 1); 

を、ActiveRecordのが理由のエラーを返しましたロック待ちタイムアウトこの単純なクエリの長​​期的な性質は同様に示唆しているようです。問題は、遅いクエリログはどこにもありません。処理に長い時間を要する実際のクエリを見つけることができます。これらはすべて上の例に似ています。さらに、この同じログでは、1つのエントリの値がLock_timeで、0より大きくはありません。

この見た目のロックを引き起こす可能性のあるアイデアは何ですか?現在使用しているツールはあまり役に立たないようです。

ありがとうございます。

+0

'show innodb status'を介して表示されている長期にわたるトランザクションはありますか?これらは暗黙的なロックを作成する可能性があり、他の場所には表示されません。 –

+0

現在存在しません。 「行ロックハッシュテーブルのロック構造体の総数」も0である。 – modulaaron

+0

私はこの同じ問題を追いかけています。私はあなたがそれを解決したとは思わない? – kwerle

答えて

4

多分これは役立ちます: http://www.mysqlperformanceblog.com/2007/02/25/pitfalls-of-converting-to-innodb/

私たちはしばしばのInnoDBにMyISAMテーブルから、現在のデータベースを変換するためにお客様にお勧めします。 ほとんどの場合、転送自体はほとんど問題ありませんが、新しい予期しないエラーによってアプリケーションが壊れる可能性があります。 1205(ER_LOCK_WAIT_TIMEOUT) ロック待ちタイムアウトが切れています。トランザクションはロールバックされました。 1213(ER_LOCK_DEADLOCK) トランザクションデッドロック。トランザクションを再実行する必要があります。

これらのエラーを処理するのは難しくありませんが、ご承知のとおりです。 これは、我々のPHPアプリケーションで行う、いくつかのものです:あなたが特に長い待ち時間が良くないWebアプリケーションのために、別の方法でER_LOCK_WAIT_TIMEOUTを処理することもできます

class mysqlx extends mysqli { 

... 

    function deadlock_query($query) { 
      $MAX_ATTEMPS = 100; 
      $current = 0; 
      while ($current++ < $MAX_ATTEMPS) { 

        $res = $this->query($query); 

        if(!$res && ($this->errno== '1205' || $this->errno == '1213' )) 
            continue; 
        else 
          break; 
      } 
} 
... 
} 

、あなたのアイデアを得ます。

関連する問題