“잠금 대기 시간 초과를 초과했습니다. 트랜잭션을 사용하지 않더라도 트랜잭션을 다시 시작하십시오”
다음 MySQL UPDATE
문을 실행 중입니다 .
mysql> update customer set account_import_id = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
거래를 사용하지 않고 있는데 왜이 오류가 발생합니까? 심지어 MySQL 서버를 다시 시작했지만 도움이되지 않았습니다.
테이블에는 406,733 개의 행이 있습니다.
거래를 사용하고 있습니다. autocommit은 트랜잭션을 비활성화하지 않고 명령문 끝에서 자동으로 커밋합니다.
일어나고있는 일이 있습니다. 다른 스레드가 일부 레코드에 대해 레코드 잠금을 유지하고 있습니다 (테이블의 모든 레코드를 업데이트 중입니다!). 스레드가 시간 초과되었습니다.
당신은 이벤트를 발행하여 이벤트에 대한 자세한 내용을 볼 수 있습니다
SHOW ENGINE INNODB STATUS
이벤트 후 ( sql
편집기에서). 이상적으로는 조용한 테스트 시스템에서이 작업을 수행하십시오.
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>;
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 초의 시간이 있으며 어떤 트랜잭션이 귀하를 잠그고 있는지 확인하십시오.
데이터베이스가 잘 조정되어 있는지 살펴보십시오. 특히 트랜잭션 격리. 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를 사용하십시오.
제안 된 해결책 중 어느 것도 나를 위해 일하지 않았지만 이것은 효과가있었습니다.
무언가 쿼리 실행을 차단하고 있습니다. 쿼리의 테이블 중 하나에서 다른 쿼리를 업데이트, 삽입 또는 삭제하는 경우가 많습니다. 그게 무엇인지 찾아야합니다.
SHOW PROCESSLIST;
차단 프로세스를 찾으면 해당 프로세스를 찾아서 id
실행하십시오.
KILL {id};
초기 쿼리를 다시 실행하십시오.
MarkR이 말한 것과 100 %. autocommit은 각 명령문을 하나의 명령문 트랜잭션으로 만듭니다.
SHOW ENGINE INNODB STATUS
교착 상태에 대한 단서를 제공해야합니다. 느린 쿼리 로그도 잘 살펴보고 테이블을 쿼리하는 다른 항목을 확인하고 전체 테이블 스캔을 수행하는 모든 것을 제거하십시오. 행 수준 잠금은 잘 작동하지만 모든 행을 잠그려고 할 때는 작동하지 않습니다!
이 테이블 내의 다른 레코드를 업데이트 할 수 있습니까? 아니면이 테이블이 많이 사용됩니까? 내가 생각하고있는 것은 설정된 시간 초과 가이 레코드를 업데이트 해야하는 잠금을 획득하려고 시도 중입니다. 도움이 될 수있는 시간을 늘릴 수 있습니다.
행 수가 많지 않습니다. 기본 키가 아닌 경우 account_import_id에 색인을 작성하십시오.
CREATE INDEX idx_customer_account_import_id ON customer (account_import_id);
데이터베이스 테이블이 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)와 비슷한 오류 메시지가 발생했습니다.
그러나 파티에 늦게까지 (평소와 같이) 내 문제는 내가 나쁜 SQL (초보자)을 썼고 여러 프로세스가 레코드에 대한 잠금을 가지고 있다는 사실이었습니다. 나는 단지 다음 SHOW PROCESSLIST
과 같이 끝내야했다.KILL <id>
PHP 언어 구문 엑시트를 사용할 때 이런 종류의 일이 일어났습니다. 거래 도중에. 그런 다음이 트랜잭션이 중단되고 mysql 프로세스를 종료해야합니다 (프로세스 목록으로 위에서 설명 함).
내 경우에는 데이터를 수정하기 위해 비정상적인 쿼리를 실행하고있었습니다. 쿼리에서 테이블을 잠그면 잠금 시간 종료를 처리하지 않아도됩니다.
LOCK TABLES `customer` WRITE;
update customer set account_import_id = 1;
UNLOCK TABLES;
이것은 정상적인 사용에는 좋지 않습니다.
자세한 정보는 MySQL 8.0 참조 매뉴얼을 참조 하십시오.
방금 큰 쿼리를 종료 한 경우 시간이 걸립니다 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
백그라운드에서 여전히 종료 된 쿼리 의 잠금 일 수 있음을 깨달았습니다 . 그래서 몇 초 기다렸다가 쿼리를 다시 실행했습니다.
나는 두 개의 Doctrine DBAL 연결을 가지고 있었는데, 그 중 하나는 비 트랜잭션 (중요한 로그의 경우)으로 연결되어 있으며 서로 의존하지 않고 병렬로 실행됩니다.
CodeExecution(
TransactionConnectionQuery()
TransactionlessConnectionQuery()
)
통합 테스트는 테스트 후 데이터 롤백을 위해 트랜잭션으로 래핑되었습니다.
beginTransaction()
CodeExecution(
TransactionConnectionQuery()
TransactionlessConnectionQuery() // CONFLICT
)
rollBack()
내 솔루션은 해당 테스트에서 래핑 트랜잭션을 비활성화하고 다른 방법으로 db 데이터를 재설정하는 것이 었습니다.
나는 Google에서 왔으며 나에게 맞는 솔루션을 추가하고 싶었습니다. 내 문제는 계단식으로 많은 FK가있는 거대한 테이블의 레코드를 삭제하려고했기 때문에 OP와 동일한 오류가 발생했습니다.
나는를 비활성화 한 autocommit
다음 COMMIT
SQL 문장 끝에 추가하면 효과가 있었습니다. 내가 이해하는 한 이것은 명령의 끝을 기다리는 대신 비트 단위로 버퍼를 해제합니다.
OP의 예를 유지하려면 다음과 같이 작동해야합니다.
mysql> set autocommit=0;
mysql> update customer set account_import_id = 1; commit;
autocommit
이전과 같이 MySQL 구성을 유지 하려면 다시 활성화하는 것을 잊지 마십시오 .
mysql> set autocommit=1;
하나의 항목으로 하나의 테이블 만 업데이트했지만 동일한 오류가 발생했지만 mysql을 다시 시작한 후 해결되었습니다.
실행중인 다른 것이 없으며 자체 인스턴스가 있다면 mysql을 다시 시작하는 것이 더 효율적이라는 것을 알았습니다.
'Programing' 카테고리의 다른 글
두 날짜 사이의 일 수를 계산하는 방법 (0) | 2020.04.16 |
---|---|
SQL 키, MUL vs PRI vs UNI (0) | 2020.04.16 |
Swift와 인터넷 연결 확인 (0) | 2020.04.16 |
트위터의 부트 스트랩을 사용하여 인라인으로 목록을 표시하는 방법 (0) | 2020.04.16 |
dispatch_async 이해 (0) | 2020.04.16 |