2017-12-10 24 views
0
  • MySQL 버전 : 5.7
  • 스토리지 엔진 : 이노
  • 이가 (nodejs에서) 카드 게임 상황에 넣을 수 있습니다. 이 경우 9 명의 선수 테이블 게임. 그리고 각 플레이어는 4 테이블 게임을 동시에 할 수 있습니다.

최근 1K 동시 사용자의 분당 1에서 5와 같은 재발 성 교착 상태가 발생했습니다. 아래 쿼리는 분당 평균 2 회 및 사용자 당 평균 2 회 호출됩니다.MySQL의 INSERT

  • 사용자가 게임하기를 원합니다.
  • 서버는 항상 1 위의 테이블 게임에서 첫 번째 빈 자리 (좌석)를 찾습니다.

이 쿼리는 2 명 이상의 다른 플레이어 (또는 동일한 플레이어 2+ 회)가 삽입 쿼리를 실행할 때 가능한 경쟁 조건을 처리하기 위해 작성 되었기 때문에 해결 방법을 모르겠습니다.

물론 고유 키를 사용하여 경쟁 조건을 처리 할 수 ​​있지만 100 개 이상의 사용자가 자유로운 장소를 검색 할 때 관리하기가 어렵습니다. 가능하면 dupplicate 키로 91+ 거부를 유발합니다.


LATEST DETECTED DEADLOCK 
------------------------ 

*** (1) TRANSACTION: 
TRANSACTION 100539324, ACTIVE 0 sec inserting 
mysql tables in use 5, locked 5 
LOCK WAIT 23 lock struct(s), heap size 3520, 111 row lock(s), undo log entries 1 
MySQL thread id 6782, OS thread handle 2460, query id 138188765 localhost 127.0.0.1 root Creating sort index 
INSERT INTO app_tables_players (user_id, game_id, seat_number, username, state, folded) SELECT 597, a.id, b.id AS seat_number, 'some_username', 'temp', false FROM (SELECT id FROM app_tables_games WHERE table_id = 6 AND seats_total > seats_taken AND id NOT IN (SELECT game_id FROM app_users_state WHERE user_id = 597)) AS a, `app_temp_players_9` AS b WHERE b.id NOT IN (SELECT seat_number FROM app_tables_players WHERE game_id = a.id) ORDER BY a.id ASC LIMIT 1 

*** (1) WAITING FOR THIS LOCK TO BE GRANTED: 
RECORD LOCKS space id 75 page no 51 n bits 1120 index seat_number_game_id of table `nodejs`.`app_tables_players` trx id 100539324 lock_mode X locks gap before rec insert intention waiting 
Record lock, heap no 964 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 1; hex 04; asc ;; 
1: len 4; hex 0008d8f6; asc  ;; 
2: len 4; hex 006b437b; asc kC{;; 

*** (2) TRANSACTION: 
TRANSACTION 100539325, ACTIVE 0 sec setting auto-inc lock, thread declared inside InnoDB 4743 
mysql tables in use 5, locked 5 
22 lock struct(s), heap size 3520, 151 row lock(s) 
MySQL thread id 6702, OS thread handle 11428, query id 138188764 localhost 127.0.0.1 root Creating sort index 
INSERT INTO app_tables_players (user_id, game_id, seat_number, username, state, folded) SELECT 613, a.id, b.id AS seat_number, 'some_username2', 'tmp', false FROM (SELECT id FROM app_tables_games WHERE table_id = 14 AND seats_total > seats_taken AND id NOT IN (SELECT game_id FROM app_users_state WHERE user_id = 613)) AS a, `app_temp_players_9` AS b WHERE b.id NOT IN (SELECT seat_number FROM app_tables_players WHERE game_id = a.id) ORDER BY a.id ASC LIMIT 1 

*** (2) HOLDS THE LOCK(S): 
RECORD LOCKS space id 75 page no 51 n bits 1120 index seat_number_game_id of table `nodejs`.`app_tables_players` trx id 100539325 lock mode S locks gap before rec 
Record lock, heap no 18 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 1; hex 06; asc ;; 
1: len 4; hex 0008d6e4; asc  ;; 
2: len 4; hex 006b5a47; asc kZG;; 

Record lock, heap no 97 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 1; hex 04; asc ;; 
1: len 4; hex 0008d97e; asc ~;; 
2: len 4; hex 006b5d1e; asc k] ;; 

Record lock, heap no 160 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 1; hex 05; asc ;; 
1: len 4; hex 0008d93e; asc >;; 
2: len 4; hex 006b4cb3; asc kL ;; 

Record lock, heap no 181 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 1; hex 04; asc ;; 
1: len 4; hex 0008d92f; asc /;; 
2: len 4; hex 006b5c0b; asc k\ ;; 

Record lock, heap no 267 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 1; hex 04; asc ;; 
1: len 4; hex 0008d9b2; asc  ;; 
2: len 4; hex 006b5b9a; asc k[ ;; 

Record lock, heap no 272 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 1; hex 05; asc ;; 
1: len 4; hex 0008d999; asc  ;; 
2: len 4; hex 006b5d43; asc k]C;; 

Record lock, heap no 307 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 1; hex 04; asc ;; 
1: len 4; hex 0008da33; asc 3;; 
2: len 4; hex 006b6182; asc ka ;; 

Record lock, heap no 346 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 1; hex 04; asc ;; 
1: len 4; hex 0008da38; asc 8;; 
2: len 4; hex 006b5fbd; asc k_ ;; 

Record lock, heap no 530 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 1; hex 05; asc ;; 
1: len 4; hex 0008d9b2; asc  ;; 
2: len 4; hex 006b544e; asc kTN;; 

Record lock, heap no 556 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 1; hex 05; asc ;; 
1: len 4; hex 0008d97e; asc ~;; 
2: len 4; hex 006b62f3; asc kb ;; 

Record lock, heap no 629 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 1; hex 04; asc ;; 
1: len 4; hex 0008d999; asc  ;; 
2: len 4; hex 006b5f41; asc k_A;; 

Record lock, heap no 804 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 1; hex 05; asc ;; 
1: len 4; hex 0008da33; asc 3;; 
2: len 4; hex 006b60bc; asc k` ;; 

Record lock, heap no 906 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 1; hex 04; asc ;; 
1: len 4; hex 0008d93e; asc >;; 
2: len 4; hex 006b4988; asc kI ;; 

Record lock, heap no 962 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 1; hex 04; asc ;; 
1: len 4; hex 0008d928; asc (;; 
2: len 4; hex 006b5b03; asc k[ ;; 

Record lock, heap no 964 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 
0: len 1; hex 04; asc ;; 
1: len 4; hex 0008d8f6; asc  ;; 
2: len 4; hex 006b437b; asc kC{;; 

*** (2) WAITING FOR THIS LOCK TO BE GRANTED: 
TABLE LOCK table `nodejs`.`app_tables_players` trx id 100539325 lock mode AUTO-INC waiting 
*** WE ROLL BACK TRANSACTION (2) 

쿼리 발생시킨 문제 :

INSERT INTO app_tables_players 
    (user_id, 
    game_id, 
    seat_number) 
SELECT 
    597, 
    a.id, 
    b.id AS seat_number 
FROM 
    (SELECT id 
    FROM 
     app_tables_games 
    WHERE 
     table_id = 14 
     AND seats_total > seats_taken 
     AND id NOT IN (
      SELECT game_id 
      FROM app_users_state 
      WHERE user_id = 597 
     ) 
    ) AS a, 
    app_temp_players_9 AS b 
WHERE 
    b.id NOT IN (
     SELECT seat_number 
     FROM app_tables_players 
     WHERE game_id = a.id 
    ) 
ORDER BY a.id ASC 
LIMIT 1; 

  • 설명 쿼리 :

,748,194,

1, INSERT, app_tables_players, , ALL, , , , , , ,

1, PRIMARY, app_tables_games, , ref, table_id,table_id_seats_taken_seats_total, table_id_seats_taken_seats_total, 4, const, 24, 33.33, Using where; Using index; Using temporary; Using filesort

1, PRIMARY, b, , index, , id, 1, , 9, 100.00, Using where; Using index; Using join buffer (Block Nested Loop)

4, DEPENDENT SUBQUERY, app_tables_players, , index_subquery, seat_number_game_id,game_id_user_id,game_id,seat_number,game_id_state, seat_number_game_id, 6, func,func, 2, 100.00, Using where; Using index

3, SUBQUERY, app_users_state, , ref, game_id_user_id,user_id,game_id, user_id, 4, const, 4, 100.00,

참고 : 때때로 교착 상태가 위의 쿼리 발생 :이 2-3 다른 유형이었다 또는 내가 본이 응용 프로그램에 직면 모든 교착 상태에 대해 좀 더 연구 한 후

DELETE FROM app_users_states WHERE game_id = some_id AND user_id = some_id 

답변

-1

상황.그 중

하나는이 lock mode AUTO-INC waiting

그래서, 첫번째 트랜잭션이 자동 증가 id 열이 잠겨 인덱스 'X', 2 거래 기다리고 인덱스 'X'와 AUTO-INC 잠금 대기에 대한 잠금을 가지고 있었다 .

lastInsertId을 얻고 나중에 SELECT에 사용하려면 id 열이 있어야하므로이 자동 증가 열이 있어야합니다. 이를 해결하기 위해 내 응용 프로그램에서 알려진 UUID 값을 만들고 autoincrement int 대신 id 바이너리 (16)로 저장했습니다.

두 번째 문제는 INSERT에서 SELECT과 같거나 다른 동일한 쿼리의 동일한 테이블에 있습니다. 같이 (siple보기);

INSERT INTO tableA some_colX (SELECT some_colY FROM tableA WHERE some_colZ = 1 LIMIT 1)

SELECT s는 lock mode S locks gap before rec을 사용하지만 INSERTlock_mode X locks gap before rec insert intention waiting이 필요합니다. 내 INSERT에서 나는 다른 테이블에있는 SELECT을 수행하고 있었고 다른 부분에는 응용 프로그램의 다른 부분에 UPDATE 또는 기타 INSERT이 있었으므로 사방에 많은 교착 상태가있었습니다.

다른 쿼리가 얻을 방지,이 이후 FOR UPDATE을 추가 INSERT 문 드 내부의 SELECT들하는 IX lock 대신 S lock의를 설정 내가 (일부)으로 변경의 일부를 해결하기 위해 먼저 X lock in this record/gap

나중에 실현

, 내 응용 프로그램에 또 다른 교착 상태가 있다는 것을. 어떻게 생각하니? 또 다른 다른 (및 최신) INSERTSELECT 다른 completly 다른 테이블에 쿼리.

1 분당 교착 상태가 1 분당 1 교착 상태에서 10 분 이상 발생합니다.

제 개인적인 의견 (유스 케이스)으로서, 동일한 쿼리에서 INSERTSELECT을 사용하지 마십시오. 절차, 트랜잭션 사용 ... 그리고 SELECT이 제대로 색인을 사용하고 있는지 확인하십시오. 제 영어 :

행운을 빌어 죄송

.

업데이트 : SELECT 테이블 중 하나에 드 INSERT 1 인덱스에 포함 된 기본 테이블에서

Chganged 1 인덱스입니다. 결과 : 2 시간 만에 교착 상태가 0 개가되었습니다.