PHP framework(Codeigniter 2.1.0)でLMSアプリケーションを開発しています。MySQLデータベースを使用しています。データベース内のすべてのテーブルにはinnodbエンジンがあり、各テーブルにインデックスも作成しています。今は私は、Jmeterバージョン2.9を使用してローカルで200人のユーザーに対して同時にローカルで負荷テストを行っています。負荷テスト中に、特定のページアクションでDeadlock Foundエラーが発生しました。元のクエリを新しいクエリに変更しましたが、同じですエラーが発生しています。
4つのパラメーターの相互作用配列を取るmodule_id、course_id、user_idのsave_interactions関数を作成し、AJAXスクリプトによって何度も呼び出されています。特定の相互作用IDがない場合、次のスクリプトはレコードを挿入します。それ以外の場合、更新クエリが起動します。
public function save_interactions($interaction_array,$modid,$cid,$uid)
{
foreach($interaction_array as $key=>$interact_value)
{
$select_query = $this->db->query("SELECT COUNT(*) AS total FROM `scorm_interactions` WHERE `mod_id`='".$modid."' AND `course_id`='".$cid."' AND `user_id`='".$uid."' AND `interaction_id`='".$interact_value[0]."'");
$fetchRow = $select_query->row_array();
if($fetchRow['total']==1)
{
$update_data = array(
"interaction_type"=>$interact_value[1],
"time"=>$interact_value[2],
"weighting"=>$interact_value[3],
"correct_response"=>$interact_value[4],
"learner_response"=>$interact_value[5],
"result"=>$interact_value[6],
"latency"=>$interact_value[7],
"objectives"=>$interact_value[8],
"description"=>$interact_value[9]
);
$this->db->where('mod_id', $modid);
$this->db->where('course_id', $cid);
$this->db->where('user_id', $uid);
$this->db->where('interaction_id', $interact_value[0]);
$this->db->update('scorm_interactions', $update_data);
}else
{
$insert_data = array(
"user_id"=>$uid,
"course_id"=>$cid,
"mod_id"=>$modid,
"interaction_id"=>$interact_value[0],
"interaction_type"=>$interact_value[1],
"time"=>$interact_value[2],
"weighting"=>$interact_value[3],
"correct_response"=>$interact_value[4],
"learner_response"=>$interact_value[5],
"result"=>$interact_value[6],
"latency"=>$interact_value[7],
"objectives"=>$interact_value[8],
"description"=>$interact_value[9]
);
$this->db->insert('scorm_interactions', $insert_data);
}
}
}
私はこのタイプのエラーを受け取りました:
ロックを取得しようとしたときにデッドロックが見つかりました。トランザクションを再開してみてください
UPDATE `scorm_interactions` SET
`interaction_type` = 'choice',
`time` = '10:45:31',
`weighting` = '1',
`correct_response` = 'Knees*',
`learner_response` = 'Knees*',
`result` = 'correct',
`latency` = '0000:00:02.11',
`objectives` = 'Question2_1',
`description` = ''
WHERE
`mod_id` = '4' AND
`course_id` = '5' AND
`user_id` = '185' AND
`interaction_id` = 'Question2_1'
;
Filename: application/models/user/scorm1_2_model.php Line Number: 234
誰かが私に回避方法を提案してくれませんかDeadlock?
PHPでの制御の流れを見てください。それは私に言います:
mod_id
、course_id
、user_id
、interaction_id
を確認してくださいINSERT
新しい行UPDATE
他のすべての列INSERTおよびUPDATEシナリオには3つのメカニズムが用意されています。
REPLACE INTO `scorm_interactions` SET
`mod_id` = '4',
`course_id` = '5',
`user_id` = '185',
`interaction_id` = 'Question2_1',
`interaction_type` = 'choice',
`time` = '10:45:31',
`weighting` = '1',
`correct_response` = 'Knees*',
`learner_response` = 'Knees*',
`result` = 'correct',
`latency` = '0000:00:02.11',
`objectives` = 'Question2_1',
`description` = ''
;
または
REPLACE INTO `scorm_interactions`
(`mod_id`,`course_id`,`user_id`,`interaction_id`,
`interaction_type`,`time`,`weighting`,`correct_response`,
`learner_response`,`result`,`latency`,`objectives`,`description`) VALUES
('4','5','185','Question2_1','choice','10:45:31','1','Knees*',
'Knees*','correct','0000:00:02.11','Question2_1','');
これは、mod_id
、course_id
、user_id
、interaction_id
に対してDELETEおよびINSERTを機械的に実行します
INSERT INTO `scorm_interactions`
(`mod_id`,`course_id`,`user_id`,`interaction_id`,
`interaction_type`,`time`,`weighting`,`correct_response`,
`learner_response`,`result`,`latency`,`objectives`,`description`) VALUES
('4','5','185','Question2_1',
'choice','10:45:31','1','Knees*',
'Knees*','correct','0000:00:02.11','Question2_1','')
ON DUPLICATE KEY UPDATE
`interaction_type` = 'choice',
`time` = '10:45:31',
`weighting` = '1',
`correct_response` = 'Knees*',
`learner_response` = 'Knees*',
`result` = 'correct',
`latency` = '0000:00:02.11',
`objectives` = 'Question2_1',
`description` = ''
;
正確に更新する予定の行に対して排他ロックを実行できることをご存知ですか?
MySQL Documentation によると、その行でSELECT
クエリを実行し、途中で行ロックを発行できます。例えば:
SELECT counter_field FROM child_codes FOR UPDATE;
UPDATE child_codes SET counter_field = counter_field + 1;
これにより、テーブル全体がロックされ、counter_field列の更新が可能になります。
あなたの場合、2つのクエリを連続して実行するだけです
SELECT * FROM `scorm_interactions`
WHERE `mod_id` = '4',
AND `course_id` = '5',
AND `user_id` = '185',
AND `interaction_id` = 'Question2_1'
FOR UPDATE ;
UPDATE `scorm_interactions` SET
`interaction_type` = 'choice',
`time` = '10:45:31',
`weighting` = '1',
`correct_response` = 'Knees*',
`learner_response` = 'Knees*',
`result` = 'correct',
`latency` = '0000:00:02.11',
`objectives` = 'Question2_1',
`description` = ''
WHERE `mod_id` = '4'
AND `course_id` = '5',
AND `user_id` = '185',
AND `interaction_id` = 'Question2_1'
;
安全策として、トラフィックが書き込みが多い場合は innodb_lock_wait_timeout を増やしてみてください。 StackOverflowの投稿を参照してください: ロック待機タイムアウトをデバッグする方法を超えましたか?
試してみる !!!