ロックのタイムアウトを引き起こしている問題のあるクエリがあります。
UPDATE <some_table> SET col1=<some value>
WHERE col1 IS NULL AND col2 > <some value>
ORDER BY col2
LIMIT 100
ここに2つの問題があります。
複数のサーバーが同時にクエリをコミットしていて、お互いにロックアウトしていて、ロックタイムアウトやデッドロックが発生することがあります。最適には、サーバーは相互に排他的な行を更新して、ロックがまったく発生しないようにする必要があります。更新でロックされた行をスキップできる方法はありますか?
ロックを回避できず、col1のインデックスとcol2のインデックスがすでにある場合、InnodbはWHERE句の任意の条件を満たすすべての行をロックしますか、または両方の条件を満たす行のみをロックしますか?答えが前者の場合、2つの列のインデックスを一緒に追加できますか、または(各列に個別に)持っているインデックスも削除する必要がありますか?
各UPDATE
の前に、自分ですべての行をロックする必要があります。
MySQLのドキュメントSELECT ... LOCK FOR UPDATE
を参照してください。これにより、通過するすべての行に対して排他ロックが実行されます。次に、テーブルに対して必要なUPDATEをフォローアップできます。
あなたの特定のケースでは、これを行うでしょう:
SELECT * FROM <some_table>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 100;
UPDATE <some_table> SET row1=<some value>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 100
SELECT ... FOR UPDATE
とUPDATE
を交互に使用する必要があります。row1
とrow2
の両方があるため、両方の列を含むインデックスが必要です。SELECT ... FOR UPDATE
とSELECT ... LOCK IN SHARED MODE
をテーマに多くの投稿があります。
Aug 08, 2011
: InnoDBデッドロックはINSERT/UPDATE/DELETE専用ですか?Oct 18, 2011
: SELECTを使用するphpアプリケーションでのmysqlデッドロックの防止…共有モードでロックJan 02, 2012
: ロックインシェアモードNov 19, 2012
: デッドロック情報がinnodbステータスページに保持できる時間Dec 13, 2012
: READ COMMITTEDであっても、MySQL InnoDBは削除時に主キーをロックしますFeb 03, 2013
: 結合されたUPDATE-JOINステートメントでのMySQL SQL InnoDBロックMar 12, 2013
: アプリケーションでのデッドロックの発生を防ぐ方法DBサーバーにアクセスする9つのWebサーバーがあるので、これを試してください。
WebServer1で実行
SELECT * FROM <some_table>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 0,100;
UPDATE <some_table> SET row1=<some value>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 0,100;
WebServer2で実行
SELECT * FROM <some_table>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 100,100;
UPDATE <some_table> SET row1=<some value>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 100,100;
WebServer3で実行
SELECT * FROM <some_table>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 200,100;
UPDATE <some_table> SET row1=<some value>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 200,100;
WebServer9に至るまで、
SELECT * FROM <some_table>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 800,100;
UPDATE <some_table> SET row1=<some value>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 800,100;
PHP一意のヘッダーファイルを配置して、どのマシンがどのバージョンのクエリを実行するかを特定する必要があります。