2016-04-29 11 views
0

私はテーブル「クリック」があり、ユーザーが特別なカウンタースクリプトclick.phpをナビゲートするたびにレコードを追加します。この表には自動インクリメント列がありません。transaction_id CHAR(32)が主キーとして使用されていますが、これは新しいレコードを挿入する前にランダムに生成されます。それぞれの新しいレコードには列normalized=0があります。MYSQL:簡単なクエリでのデッドロック

3分ごとのバックグラウンドデーモンがトランザクションを開始し、すべての新規クリックWHERE normalized=0を読み取り、テーブルstatsにグループ化します。そのテーブルの書き込みクエリは、すべての処理の最後に実行された後にトランザクションコミットされるUPDATE clicks SET normalized=1 WHERE normalized=0です。

問題がclick.phpが、このトランザクション中にナビゲートされるたびに、スクリプトは「クリック」に新しいレコードを追加することができないということであり、エラーで失敗します。

SQLSTATE[40001]: Serialization failure: 
1213 Deadlock found when trying to get lock; try restarting transaction 

    INSERT `clicks` 
    SET `transaction_id`='3520359d597ba05b635ff15feb334229', 
     `time`='2016-04-29 15:14:31', 
     ..., 
     `normalized`='0' 

私はこの問題を解決することができます知っていますLOCK TABLESを使用していますが、なぜこのデッドロックが発生するのかを知りたいだけです。

UPD: 私は、SHOW ENGINEのINNODBのSTATUS出力の理由は、以下を参照してください:

*** (1) WAITING FOR THIS LOCK TO BE GRANTED: 
RECORD LOCKS space id 252763 page no 124 n bits 480 index `normalized` 
of table `tds`.`clicks` trx id C1329EF lock_mode X locks gap before 
rec insert intention waiting 

答えて

0

は(これはコメントする必要がありますが、しかし、その長いと関わっ)

トランザクション分離モードは何ですか?

私はこれまでにこれまでに遭遇したことはありません。主にmutli文トランザクションを使用しないようにしています。

UPDATE clicks 
SET normalized=2 
WHERE normalized=0; 

INSERT INTO stats (transaction_id, clicks) 
SELECT transaction_id, COUNT(*) 
FROM clicks 
WHERE normalized=2 
GROUP BY transaction_id; 

UPDATE clicks 
SET transaction_id=1 
WHERE transaction_id=2; 

あなたが別々の列とデータセットの生成された識別子を使用している場合はクリックテーブルに単一の更新でこれを行う方法があります。これをcronから実行している場合は、これらをGET_LOCK()... RELEASE_LOCK()サイクルでラップして、並行処理を防ぐ必要があります。このモデルでは、ほとんどのトランザクションモデルで同時実行性がサポートされていますが、状況が悪くなっているときにパフォーマンスが低下します。

関連する問題