2011-10-27 2 views
0

私のアプリケーションでは、デッドロックの原因となる(異なるプロセスから)2つのクエリが時々発生します。これらのクエリのロックモードSとXのInnoDBデッドロック

クエリ#1

UPDATE tblA, tblB SET tblA.varcharfield=tblB.varcharfield WHERE tblA.varcharfield IS NULL AND [a few other conditions]; 

クエリ#2

INSERT INTO tmp_tbl SELECT * FROM tblA WHERE [various conditions]; 

これらの両方のテーブルが数百万行を持っているように、かなりの時間を要します。クエリ#2が実行されているときは、StblAがロックされているようです。クエリ#1にはXのロックが必要です。これはSロック、クエリ#私はデッドロックを取得した時点で、最大30秒間待つ、と互換性がありませんので:

シリアル化の失敗:ロックを取得しようとしたときに1213デッドロックが見つかりました。私はin the documentation読んだに基づいて取引

を再起動してみてください、私はカップルのオプションを持っていると思う:

  1. がtblA.varcharfieldにインデックスを設定します。残念ながら、私は、これはvarchar(512)のフィールドを格納するために非常に大きなインデックスが必要になると思います。 (下記の編集を参照してください...これは機能しませんでした)
  2. SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; でロックを無効にしてください。私はこれの意味を理解していないし、破損したデータが心配です。私は現在、私のアプリケーションで明示的なトランザクションを使用していませんが、私はいつか将来的にはそうかもしれません。
  3. 時間のかかるクエリを小さな断片に分割し、30秒のタイムアウトに達することなくMySQLでキューに入れて実行できるようにします。これは実際に問題の中心を修正するものではなく、私のデータベースサーバがビジー状態になって問題が再発することが懸念されます。
  4. クエリを何度もやり直してください...私が望んでいるオプションではありません。

どうすればよいですか?私が検討すべき別の方法がありますか?


EDIT:私はvarcharfieldにインデックスを設定しようとしたが、テーブルはまだロックしています。私は、部分が実際に実行されているときにロックが発生すると思われます。この問題を回避するための他の提案はありますか?

答えて

0

:ちょうどインデックスのサイズを指定します。これは、各クエリが非常に多くのレコードに影響を及ぼし、これらの両方がバックグラウンドプロセスであるため、より良い解決策であることが判明しました。彼らは今、お互いに待っています。

http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html

これは私にとってはいい解決策であるが、それは明らかに皆のための答えではありません。 WRITEでロックすると、READにアクセスできなくなります。 READロックのみ他人にREADを許可します。

1

A.私たちはインデックスvarcharFieldが多くのディスク領域を受け取り、新しい列を追加すると、私は次のようなアプローチを提案することができますハードあなたをヒットしないだろうと仮定した場合:

  1. データ型「tinyint型」と
  2. を新しいフィールドを作成します
  3. それをインデックスします。
  4. varcharFieldがnullの場合は0、それ以外の場合はこのフィールドに0が格納されます。
  5. 新しいフィールドに依存する更新を行う最初のクエリを書き換えます。この場合、テーブルロック全体が発生することはありません。

希望します。

+0

ありがとうございます。私はDarhazerが提案したようにインデックスを使用しようとしましたが、役に立たない。私は 'UPDATE'が' SELECT'を実行する前に実行しなければならないと思っています。他のアドバイスはありますか? – Brad

+0

まだ問題がある場合は、 'show innodb status'、デッドロックのセクションを入れてください。 – ravnur

+0

ありがとうございます。私はテーブルを明示的にロックすることで問題を解決しました。残念ながら、デッドロックは、NDAのために公開できないクエリの他の部分によって引き起こされているに違いないと思います。問題の質問の単純化は適切ではありませんでした。私はあなたの助けを借りて、この問題を解決することに感謝します。 – Brad

1

varcharカラムの一部だけにインデックスを付けることはできますが、それでも機能し、必要なスペースは少なくなります。私は両方のクエリーの周りに明示的なLOCK TABLE文を追加することによって、問題を解決することができた

CREATE INDEX someindex ON sometable (varcharcolumn(32)) 
+0

アドバイスをいただきありがとうございます。私はこの昨夜を試みたが、まだデッドロックを取得しています。私は 'SELECT'クエリで' EXPLAIN'を実行しました、そして、彼らはすべて期待どおりのインデックスを使用しています。私は 'UPDATE'が' SELECT'がまったく動作する前に実行しなければならないと思っています。 – Brad

+0

@ブラッド質問に説明を追加できますか?私はそれらを見てみたいです –

+0

あなたの助けに大変感謝します。テーブルを明示的にロックすることでこの問題を回避することができました。問題はNDAのために公表することができない質問の一部だと思うし、質問の簡素化で問題が適切に表示されなかった。あなたの助けをもう一度ありがとう! – Brad

関連する問題