2011-08-31 4 views
2

I 다음 표MySQL의 InnoDB의 교착 상태 문제

CREATE TABLE IF NOT EXISTS `task` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `job_id` int(10) unsigned NOT NULL COMMENT 'The id of the related job', 
    `server_id` tinyint(4) NOT NULL DEFAULT '0' COMMENT 'job/task owner', 
    `jobtype_id` int(10) unsigned NOT NULL DEFAULT '0', 
    `node_id` int(10) unsigned NOT NULL COMMENT 'The id of the user currently executing this task', 
    `status` enum('QUEUED','EXECUTING','COMPLETED','CANCELED','TERMINATED','PAUSED','FAILED') NOT NULL COMMENT 'Current status of the task', 
    `last_updated` int(11) NOT NULL COMMENT 'When was the last status change of this task. Used in requeueing hung tasks', 
    `data_in` blob NOT NULL COMMENT 'An input data to the task. Sets when the task is created.', 
    `data_out` blob NOT NULL COMMENT 'An output data of the task. Sets upon task completion. Can be absent.', 
    `speed` bigint(20) unsigned NOT NULL DEFAULT '0', 
    `time_spent` int(11) NOT NULL DEFAULT '0', 
    `has_data_out` tinyint(1) NOT NULL COMMENT 'Shows if the task has any output data. Serves caching purposes. Used by Summarizers to quickly find out what tasks of the job yielded data.', 
    `comment` varchar(200) NOT NULL DEFAULT '', 
    PRIMARY KEY (`id`), 
    KEY `fk_task_job_id` (`job_id`), 
    KEY `index_has_data_out` (`has_data_out`), 
    KEY `index_last_updated` (`last_updated`), 
    KEY `index_status` (`status`), 
    KEY `fk_task_userid` (`node_id`), 
    KEY `jobtype_id` (`jobtype_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='This table holds all subjobs - tasks' AUTO_INCREMENT=1081595 ; 

-- 
-- Constraints for dumped tables 
-- 

-- 
-- Constraints for table `task` 
-- 
ALTER TABLE `task` 
    ADD CONSTRAINT `task_ibfk_5` FOREIGN KEY (`job_id`) REFERENCES `job` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, 
    ADD CONSTRAINT `task_ibfk_7` FOREIGN KEY (`jobtype_id`) REFERENCES `jobtype` (`id`), 
    ADD CONSTRAINT `task_ibfk_8` FOREIGN KEY (`node_id`) REFERENCES `node` (`id`); 

그리고 다음과 같은 교착 상태에 문제가 있습니다

------------------------ 
LATEST DETECTED DEADLOCK 
------------------------ 
110831 14:23:56 
*** (1) TRANSACTION: 
TRANSACTION 102B4D2, ACTIVE 0 sec, OS thread id 5480 
mysql tables in use 2, locked 1 
LOCK WAIT 7 lock struct(s), heap size 1248, 4 row lock(s), undo log entries 3 
MySQL thread id 74315, query id 2364347 192.168.1.120 usr_sl3 Sending data 
select `usr_sl3`.`task`.`id` from `usr_sl3`.`task` where (`usr_sl3`.`task`.`node_id` = 103 and `usr_sl3`.`task`.`status` = 'EXECUTING') for update 
*** (1) WAITING FOR THIS LOCK TO BE GRANTED: 
RECORD LOCKS space id 38 page no 2303 n bits 576 index `index_status` of table `usr_sl3`.`task` trx id 102B4D2 lock_mode X locks rec but not gap waiting 
Record lock, heap no 471 PHYSICAL RECORD: n_fields 2; compact format; info bits 32 
0: len 1; hex 02; asc ;; 
1: len 4; hex 00107dac; asc } ;; 

*** (2) TRANSACTION: 
TRANSACTION 102B4D3, ACTIVE 0 sec, OS thread id 5692 starting index read, thread declared inside InnoDB 500 
mysql tables in use 2, locked 1 
7 lock struct(s), heap size 1248, 4 row lock(s), undo log entries 3 
MySQL thread id 74354, query id 2364348 192.168.1.120 usr_sl3 Sending data 
select `usr_sl3`.`task`.`id` from `usr_sl3`.`task` where (`usr_sl3`.`task`.`node_id` = 95 and `usr_sl3`.`task`.`status` = 'EXECUTING') for update 
*** (2) HOLDS THE LOCK(S): 
RECORD LOCKS space id 38 page no 2303 n bits 576 index `index_status` of table `usr_sl3`.`task` trx id 102B4D3 lock_mode X locks rec but not gap 
Record lock, heap no 471 PHYSICAL RECORD: n_fields 2; compact format; info bits 32 
0: len 1; hex 02; asc ;; 
1: len 4; hex 00107dac; asc } ;; 

*** (2) WAITING FOR THIS LOCK TO BE GRANTED: 
RECORD LOCKS space id 38 page no 2303 n bits 576 index `index_status` of table `usr_sl3`.`task` trx id 102B4D3 lock_mode X locks rec but not gap waiting 
Record lock, heap no 481 PHYSICAL RECORD: n_fields 2; compact format; info bits 32 
0: len 1; hex 02; asc ;; 
1: len 4; hex 00107dab; asc } ;; 

*** WE ROLL BACK TRANSACTION (2) 

당신의 메커니즘을 이해하는 데 도움 주실 래요에게 이 교착 상태?

두 개의 쿼리는 서로 다른 스레드에서 발행됩니다. 각 스레드는 쿼리에서 자체 node_id를가집니다. 두 개의 u 리에 동일한 node_id가 없습니다.

필자는 필드 (node_id, status)에 복합 인덱스를 작성하여 문제를 해결할 수 있다고 생각하지만 이는 좋은 해결책이 아닙니다. 나는 문제의 본질을 이해할 필요가있다.

동일한 쿼리에서 이러한 교착 상태는 한두 번이 아닌 주기적으로 발생합니다. 영향을받는 쿼리에

EXPLAIN 흥미로운 결과를 제공합니다 :

id select_type  table type possible_keys key  key_len  ref  rows Extra 
1 SIMPLE task index_merge  index_status,fk_task_userid  index_status,fk_task_userid  1,4  NULL 1 Using intersect(index_status,fk_task_userid); Using where; Using index 

MySQL 버전은 5.5입니다.

도 교착 순간에, 테이블 usr_sl3를 선택하여 해당 질의의 조건 (예를 들어, 일치하는 행을 포함하지 않는다. task. idusr_sl3부터. (usr_sl3. tasktask한다. node_id = 95 usr_sl3있다. task. status = 'EXECUTING') 업데이트 에 대한 행을 전혀 얻지 않습니다.

미리 감사드립니다.

답변

1

쿼리는 fk_task_userid (node_id의 인덱스) 대신 index_status 인덱스를 사용합니다. 이것이 다른 node_ids로 레코드를 잠그는 이유입니다. 당신은 실제로 당신이 잠글 필요가 얼마나 많은 이들의 대 (조사 행) 잠금 얼마나 많은 기록을 확인하기 위해 쿼리를 설명 실행할 수 있습니다

내가 해결할 수 있다는 생각

(행 반환) 상황 (node_id, 상태) 필드에 복합 인덱스를 작성하여 상황, 그러나 이것은 좋은 해결책이 아닌 것 같아요. 나는 문제의 본질을 이해할 필요가있다.

왜? 어쨌든 귀하의 인덱스가 최적이 아닌 것 같아요 ... node_id, 상태에 인덱스를 작성하면 문제가 해결됩니다.

+0

EXPLAIN 결과를 질문에 추가했습니다. 쿼리는이 쿼리에서 index_merge 또는 인덱스 교차를 사용합니다. –

+1

두 개의 mysql 클라이언트를 사용하여 테스트를 수행했으며 index_merge를 사용하면 첫 번째 인덱스와 일치하는 모든 행이 잠겨 있으므로 일치하는 행만 잠글 수 있도록 복합 인덱스 IS가 필요합니다. – ColinM