“잠금 대기 시간 초과를 초과했습니다. 트랜잭션을 사용하지 않더라도 트랜잭션을 다시 시작하십시오”


267

다음 MySQL UPDATE문을 실행 중입니다 .

mysql> update customer set account_import_id = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

거래를 사용하지 않고 있는데 왜이 오류가 발생합니까? 심지어 MySQL 서버를 다시 시작하려고 시도했지만 도움이되지 않았습니다.

테이블에는 406,733 개의 행이 있습니다.

답변:


211

거래를 사용하고 있습니다. autocommit은 트랜잭션을 비활성화하지 않고 명령문 끝에서 자동으로 커밋합니다.

일어나고있는 일이 있습니다. 다른 스레드가 일부 레코드에 대해 레코드 잠금을 유지하고 있습니다 (테이블의 모든 레코드를 업데이트 중입니다!). 스레드가 시간 초과되었습니다.

당신은 이벤트를 발행하여 이벤트에 대한 자세한 내용을 볼 수 있습니다

SHOW ENGINE INNODB STATUS

이벤트 후 ( sql편집기에서). 이상적으로는 조용한 테스트 시스템에서이 작업을 수행하십시오.


1
출력을 파일로 저장하는 방법이 있습니까? SHOW ENGINE INNODB STATUS \ G> innodb_stat.txt를 시도했지만 작동하지 않습니다.
yantaq

14
명령 행에서 : mysql [insert credentials] -e "SHOW ENGINE INNODB STATUS \ G"> innodb_stat.txt
VenerableAgents

많은 mysql 스레드 (또는 프로세스)가 사용중인 경우, 예를 들어 일부 쿼리에는 매우 오랜 시간이 필요하므로 일부 process유휴 상태 를 기다려야 합니다. 그렇다면이 오류가 발생할 수 있습니다. 내가 맞아?
zhuguowei

6
단일 트랜잭션 중 동일한 행에서 여러 (2+) 개의 UPDATE 쿼리를 실행하면이 오류가 발생합니다.
Okneloper

Python MySQL Connector를 사용 connection.commit()하는 사용자는 커밋 INSERT하거나 UPDATE방금 완료했습니다.
AER

334

MySQL에서 잠긴 테이블의 잠금을 해제하는 방법 :

이와 같은 잠금을 해제 하면 데이터베이스의 원 자성 이 잠금 을 유발 한 SQL 문에 적용되지 않을 수 있습니다.

이것은 hackish이며 올바른 해결책은 잠금을 유발 한 응용 프로그램을 수정하는 것입니다. 그러나, 달러가 온라인에있을 때, 빠른 킥은 물건을 다시 움직일 것입니다.

1) MySQL 입력

mysql -u your_user -p

2) 잠긴 테이블 목록을 보자

mysql> show open tables where in_use>0;

3) 현재 프로세스 목록을 보자. 그 중 하나는 테이블을 잠그고 있습니다.

mysql> show processlist;

4)이 프로세스 중 하나를 종료

mysql> kill <put_process_id_here>;

14
이것은 위험하고 해킹입니다. 적절한 해결책은 응용 프로그램을 수정하는 것입니다.
Zenexer

71
말도 안되는 일로, 엉망을 취소하고 응용 프로그램을 수정할 수 있습니다. 이 녀석에게이 문제에 대해 100 표를 줄 수 있다면 지금 고쳐야합니다.
Lizardx

7
나는 Lizardx에 동의합니다. 이것은 SHOW ENGINE INNODB STATUS
Travis Schneeberger에

8
장기 실행 쿼리를 이런 식으로 죽이는 것은 어떻게 위험 합니까? 클라이언트 호출에 오류가 발생합니다.
Xeoncross

7
@EricLeschinski 나는 당신의 요점을 얻었지만, 왜 세상 에서 Life-Critical 시스템 에서 MySQL 과 같은 조잡한 데이터베이스를 사용해야 할까요?
Xeoncross

96
mysql> set innodb_lock_wait_timeout=100

Query OK, 0 rows affected (0.02 sec)

mysql> show variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 100   |
+--------------------------+-------+

이제 잠금을 다시 트리거하십시오. SHOW ENGINE INNODB STATUS\G데이터베이스에 a를 발행하는 데 100 초의 시간이 있으며 어떤 트랜잭션이 귀하를 잠그는 지 확인하십시오.


8
이 답변은 왜 asker에 오류가 있는지 설명하지 않습니다. 답을주는 것 외에 왜 그런지 자세히 설명해 주시겠습니까?
썰매

5
+1이 질문에 직접 대답하지는 않지만이 문제를 해결하는 좋은 참고 자료입니다.
Jossef Harush

1
@ArtB dev.mysql.com/doc/innodb/1.1/en/... 잠금이 테이블과 트랜잭션을 종료 될 때까지의 시간에 호출 된 때문에 영업 이익은 오류를 수신 본질적으로는 초과 lock_wait_timeout
fyrye을

70

데이터베이스가 잘 조정되어 있는지 살펴보십시오. 특히 트랜잭션 격리. innodb_lock_wait_timeout 변수를 늘리는 것은 좋지 않습니다.

mysql cli에서 데이터베이스 트랜잭션 격리 레벨을 확인하십시오.

mysql> SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation, @@session.transaction_isolation;
+-----------------------+-----------------+------------------------+
| @@GLOBAL.tx_isolation | @@tx_isolation  | @@session.tx_isolation |
+-----------------------+-----------------+------------------------+
| REPEATABLE-READ       | REPEATABLE-READ | REPEATABLE-READ        |
+-----------------------+-----------------+------------------------+
1 row in set (0.00 sec)

분리 레벨을 변경하여 개선을 얻을 수 있습니다. READ COMMITTED와 같은 오라클을 대신 반복 읽기 (InnoDB 기본값)로 사용하십시오.

mysql> SET tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> 

필요한 경우에만 SELECT FOR UPDATE를 사용하십시오.


1
이것은 잠금 문제에 대한 훌륭한 솔루션입니다.
연상

3
my.cnf 버전은 [mysqld]입니다. transaction-isolation = READ-COMMITTED
Benoit Gauthier

참고 사항 : MySQL 8의 tx_isolation변수 이름이로 변경 되었습니다 transaction_isolation.
xonya

읽기 격리에서 읽기 커밋으로 변경할 때 어떤 일이 벌어지고 있는지 알기 위해주의를 기울여야합니다. 피해야 할 더티 데이터가 생길 수 있습니다. Wikipedia Isoloation
huggie

27

제안 된 해결책 중 어느 것도 나를 위해 일하지 않았지만 이것은 효과가있었습니다.

쿼리 실행을 방해하는 것이 있습니다. 쿼리의 테이블 중 하나에서 다른 쿼리를 업데이트, 삽입 또는 삭제하는 경우가 많습니다. 그게 무엇인지 찾아야합니다.

SHOW PROCESSLIST;

차단 프로세스를 찾으면 해당 프로세스를 찾아서 id실행하십시오.

KILL {id};

초기 쿼리를 다시 실행하십시오.


SHOW PROCESSLIST에 나열된 모든 프로세스를 실수로 종료했습니다. 이제 phpmyadmin에서 500 오류가 발생합니다. 이 프로세스를 죽이는 것과 관련된 500 오류입니까? 그렇다면 어떻게 다시 시작할 수 있습니까?
Dashrath

나는 당신이 묘사 한 것을 볼 수 있지만 프로세스를 죽이는 것은 효과가 없습니다. 프로세스의 명령은 "killed"이지만 프로세스 목록에 남아 있습니다.
Torsten

12

MarkR의 말과 100 %. autocommit은 각 명령문을 하나의 명령문 트랜잭션으로 만듭니다.

SHOW ENGINE INNODB STATUS교착 상태에 대한 단서를 제공해야합니다. 느린 쿼리 로그도 잘 살펴보고 테이블을 쿼리하는 다른 항목을 확인하고 전체 테이블 스캔을 수행하는 모든 것을 제거하십시오. 행 수준 잠금은 잘 작동하지만 모든 행을 잠그려고 할 때는 작동하지 않습니다!


5

이 테이블 내의 다른 레코드를 업데이트 할 수 있습니까? 아니면이 테이블이 많이 사용됩니까? 내가 생각하고있는 것은 잠금을 얻으려고 시도하는 동안 설정된 시간 초과 가이 레코드를 업데이트해야한다는 것입니다. 도움이 될 수있는 시간을 늘릴 수 있습니다.


3
어쩌면 innodb_lock_wait_timeout에서my.cnf
oblig

1
my.cnf에서 설정했습니다 : <br/> innodb_lock_wait_timeout = 120 <br/> mysql 5.5의 기본값은 50입니다. 이 변경 후 단위 테스트에서이 문제를 볼 수 없었습니다! 이것은 proxool에서 tomcat jdbc pool로 전환 한 후에 발생했습니다. 아마도 Tomcat Pool과의 거래 시간이 더 길어?!
챔프

3

행 수가 많지 않습니다. 기본 키가 아닌 경우 account_import_id에 색인을 작성하십시오.

CREATE INDEX idx_customer_account_import_id ON customer (account_import_id);

세상에 ... 이것은 저를 구했습니다. 인덱스를 삭제하여 프로덕션 DB를 왕실로 조이면서 수정했습니다. 감사합니다.
Nick Gotch

2

방금 큰 쿼리를 종료 한 경우 시간이 걸립니다 rollback. 종료 된 조회가 롤백되기 전에 다른 조회를 발행하면 잠금 시간 종료 오류가 발생할 수 있습니다. 그것이 저에게 일어난 일입니다. 해결책은 조금만 기다려야했습니다.

세부:

약 1 백만 행 중 약 900,000을 제거하기 위해 DELETE 쿼리를 발행했습니다.

실수로 이것을 실행했습니다 (행의 10 % 만 제거). DELETE FROM table WHERE MOD(id,10) = 0

이 대신 행의 90 %를 제거합니다. DELETE FROM table WHERE MOD(id,10) != 0

10 %가 아닌 90 %의 행을 제거하고 싶었습니다. 그래서 지금까지 삭제 한 모든 행을 롤백한다는 것을 알고 MySQL 명령 줄에서 프로세스를 종료했습니다.

그런 다음 올바른 명령을 즉시 실행하고 lock timeout exceeded곧 오류가 발생했습니다. 잠금은 실제로 rollback백그라운드에서 여전히 종료 된 쿼리 의 잠금 일 수 있음을 깨달았습니다 . 그래서 몇 초 기다렸다가 쿼리를 다시 실행했습니다.


1

데이터베이스 테이블이 InnoDB 스토리지 엔진과 READ-COMMITTED 트랜잭션 격리 수준을 사용하고 있는지 확인하십시오.

SELECT @@ GLOBAL.tx_isolation, @@ tx_isolation로 확인할 수 있습니다. mysql 콘솔에서.

READ-COMMITTED로 설정되어 있지 않으면 설정해야합니다. mysql에 SUPER 권한이 있는지 설정하기 전에 확인하십시오.

http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html 에서 도움을받을 수 있습니다 .

이것을 설정하면 문제가 해결 될 것이라고 생각합니다.


두 프로세스에서 한 번에 업데이트하지 않으려는지 확인할 수도 있습니다. 이 컨텍스트에서 사용자 (@tala)와 비슷한 오류 메시지가 발생했습니다.


1

나는 Google에서 왔으며 나에게 맞는 솔루션을 추가하고 싶었습니다. 내 문제는 캐스케이드에 많은 FK가있는 거대한 테이블의 레코드를 삭제하려고했기 때문에 OP와 동일한 오류가 발생했습니다.

나는 비활성화하고 SQL 문장 끝에 autocommit추가하면 효과가 COMMIT있었습니다. 내가 이해하는 한 이것은 명령의 끝을 기다리는 대신 비트 단위로 버퍼를 해제합니다.

OP의 예를 유지하려면 다음과 같이 작동해야합니다.

mysql> set autocommit=0;

mysql> update customer set account_import_id = 1; commit;

autocommit이전과 같이 MySQL 구성을 유지 하려면 다시 활성화하는 것을 잊지 마십시오 .

mysql> set autocommit=1;


0

그러나 파티에 늦게 (평소와 같이) 내 문제는 내가 나쁜 SQL (초보자)을 썼고 여러 프로세스가 레코드에 대한 잠금을 가지고 있다는 사실이었습니다. 나는 단지 다음 SHOW PROCESSLIST과 같이 끝내야했다.KILL <id>


0

PHP 언어 구문 엑시트를 사용할 때 이런 종류의 일이 일어났습니다. 거래 도중에. 그런 다음이 트랜잭션이 중단되고 mysql 프로세스를 종료해야합니다 (프로세스 목록으로 위에서 설명 함).


0

내 경우에는 데이터를 수정하기 위해 비정상적인 쿼리를 실행하고있었습니다. 쿼리에서 테이블을 잠그면 잠금 시간 종료를 처리하지 않아도됩니다.

LOCK TABLES `customer` WRITE;
update customer set account_import_id = 1;
UNLOCK TABLES;

이것은 정상적인 사용에는 좋지 않습니다.

자세한 정보는 MySQL 8.0 참조 매뉴얼을 참조 하십시오.


0

나는 두 개의 Doctrine DBAL 연결을 가지고 있었는데, 그 중 하나는 비 트랜잭션 (중요한 로그의 경우)으로 서로 연결되지 않고 병렬로 실행됩니다.

CodeExecution(
    TransactionConnectionQuery()
    TransactionlessConnectionQuery()
)

통합 테스트는 테스트 후 데이터 롤백을 위해 트랜잭션으로 래핑되었습니다.

beginTransaction()
CodeExecution(
    TransactionConnectionQuery()
    TransactionlessConnectionQuery() // CONFLICT
)
rollBack()

내 솔루션은 해당 테스트에서 래핑 트랜잭션을 비활성화하고 다른 방법으로 db 데이터를 재설정하는 것이 었습니다.


-4

하나의 항목으로 하나의 테이블 만 업데이트했지만 동일한 오류가 발생했지만 mysql을 다시 시작한 후에는 해결되었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.