1

これについて専門家のアドバイスが必要です。

背景 PHP/Codeigniter MYSQLi Innodb テーブル - fares_table ストアド プロシージャ

バックエンド - 数分ごとに fares_table に (サービスからの) データを挿入/更新する cronjob php スクリプトが書き込まれます。(通常の SQL クエリ)

フロントエンド - ユーザーはこれらのデータを読み取ることができます (多くのテーブルの結合を伴うため、クエリはストアド プロシージャ形式で記述されます。したがって、私のストアド プロシージャは、fares_table の select ステートメントから一時テーブルを作成し、他のテーブルに結合しています)

問題

ロックを取得しようとしたときにデッドロックが見つかりました。トランザクションを再開してみてください

fares_table の更新/挿入中にユーザーがフロントエンドに出くわした場合、デッドロックが発生する可能性があります。update ステートメントでデッドロックが発生する

デッドロックは、バックエンドが挿入または更新を行ってロックが解放されるのを待機しようとしている間に、fares_table からの選択ステートメントを使用して一時テーブルを作成しようとしているときに、ストアド プロシージャがロックが解放されるのを待機しようとすることによって発生します。

LATEST DETECTED DEADLOCK
------------------------
110408  9:05:45
*** (1) TRANSACTION:
TRANSACTION 0 203543446, ACTIVE 0 sec, OS thread id 6584 fetching rows
mysql tables in use 2, locked 2
LOCK WAIT 761 lock struct(s), heap size 60736, 30170 row lock(s)
MySQL thread id 86268, query id 135039790 XXXXXXX Copying to t
CREATE TEMPORARY TABLE tmp_tb1 AS SELECT MIN( fare ) as cheapest_fare,flighttype origin,destination ....
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 18433 n bits 240 index `PRIMARY` of table `db_name`.`fares_table`
Record lock, heap no 85 PHYSICAL RECORD: n_fields 18; compact format; info bits 0
0: len 4; hex 8025d996; asc  %  ;; 1: len 6; hex 00000c21d3a9; asc    !  ;; 2: len 7; hex 0000000b031

*** (2) TRANSACTION:
TRANSACTION 0 203543465, ACTIVE 0 sec, OS thread id 3080 updating or deleting, thread declared inside
mysql tables in use 1, locked 1
3 lock struct(s), heap size 320, 2 row lock(s), undo log entries 1
MySQL thread id 85631, query id 135039816 XXXXX Updating
UPDATE `fares_table` SET `fare` = 2552.85, `currency` = 'AUD'..
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 18433 n bits 240 index `PRIMARY` of table `db_name`.`fares_table`
Record lock, heap no 85 PHYSICAL RECORD: n_fields 18; compact format; info bits 0
0: len 4; hex 8025d996; asc  %  ;; 1: len 6; hex 00000c21d3a9; asc    !  ;; 2: len 7; hex 0000000b031

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 2086 n bits 600 index `flighttype_idx` of table `db_name`.`fares_table`
Record lock, heap no 218 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
0: len 7; hex 4f6e6520776179; asc One way;; 1: len 3; hex 424e45; asc BNE;; 2: len 8; hex 8000124a588

*** WE ROLL BACK TRANSACTION (2)

私の一時的な修正

データベース エラー 1213 をキャッチし、更新クエリを再試行します。現在は機能していますが、代わりにデッドロックを防ぐためのより良い解決策を見つけたいと思います。専門的なアドバイスはありますか?

デッドロックを防ぐために順序を変更するにはどうすればよいですか?またはインデックスの複製がflighttype_idx役立ちますか?

4

1 に答える 1

0

一時テーブルを作成するためのクエリは、基本的に集計関数のためにテーブルの主要部分をロックMIN(fare)する必要があり、料金の更新はそれが完了するまで待機する必要があるため、デッドロックを解決できる単純な並べ替えはありません。

トランザクションを競合させてからロールバックするよりも、おそらくこの目的のためだけにロック テーブルで、明示的なロック メカニズムによって競合を囲む方がよいでしょう。特に、create table ステートメントはロールバックできません。奇妙に思えるかもしれません。LOCK TABLE のドキュメントを参照してください。

整然と実装するには、運賃更新ステートメントをストアド プロシージャに移動し、運賃更新と一時テーブル作成のストアド プロシージャをロックのチェックと設定、作業の実行、およびロック解除でループさせます。

于 2011-04-11T05:09:36.600 に答える