source

Django & MariaDB / MySQL : select_for_update lock 행을 서브쿼리에서 선택합니까?교착상태의 원인?

gigabyte 2022. 9. 8. 22:22
반응형

Django & MariaDB / MySQL : select_for_update lock 행을 서브쿼리에서 선택합니까?교착상태의 원인?

소프트웨어:Django 2.1.0, Python 3.7.1, MariaDB 10.3.8, Linux Ubuntu 18LTS

최근 새로운 애플리케이션에 부하를 추가하여 많은 교착 상태를 관찰하기 시작했습니다.자세히 조사한 결과, Django select_for_update 쿼리에서 여러 개의 서브쿼리(3 또는 4)를 가진 SQL이 생성되었음을 알 수 있었습니다.지금까지 본 모든 교착상태에서 트랜잭션 중 적어도 하나는 이 SQL에 여러 개의 하위 쿼리가 포함되어 있습니다.

제 질문은... select_for_udpate는 관련된 모든 테이블에서 레코드를 잠급니까?제 경우 메인 SELECT에서 녹음을 하고 서브쿼리에서 사용되는 다른 테이블에서 녹음이 잠기나요?아니면 메인 SELECT의 레코드만?

Django 문서에서:

기본적으로는 select_for_update()는 쿼리에 의해 선택된 모든 행을 잠급니다.예를 들어 select_related()에서 지정된 관련 객체의 행은 쿼리셋 모델의 행과 함께 잠깁니다.

단, select_related()는 사용하지 않습니다.적어도 명시적으로 입력하지는 않습니다.

내 앱 요약:

with transaction.atomic():
   ModelName.objects.select_for_update().filter(...)
   ...
   update record that is locked
   ...
  • 50개 이상의 클라이언트가 동시에 데이터베이스로 쿼리를 전송
  • 이러한 쿼리 중 일부는 동일한 기록을 요구합니다.즉, 서로 다른 트랜잭션이 동시에 동일한 SQL을 실행합니다.

많은 책을 읽은 후, 저는 교착 상태를 극복하기 위해 다음과 같이 했습니다.

1- 예외 오류 '1213'(데드록)을 시도/캐치합니다.이 경우 30초 동안 기다린 후 쿼리를 재시도하십시오.여기서는 데이터베이스 엔진의 Rollback 기능에 의존합니다.또한 SHOW ENGINE INNODB STATUS 출력과 SHOW PROCESSLIST 출력은 출력되지만 SHOW PROCESSLIST는 유용한 정보를 제공하지 않습니다.

2- Django select_on_update를 수정하여 하위 쿼리를 사용하여 SQL을 빌드하지 않도록 합니다.생성된 SQL에는 값이 있고 하위 쿼리가 없는 단일 WHERE가 포함됩니다.

교착 상태를 줄이기 위해 할 수 있는 다른 방법은 없나요?

u hv 트랜잭션 내에서 select_for_update를 선택하면 트랜잭션 커밋 또는 롤백 전체를 통해서만 해제됩니다.nowait가 true로 설정되면 다른 동시 요청은 즉시 실패합니다. 3572 "Statement aborted becaused 왜냐하면 lock(s)을 즉시 획득할 수 없고 NOWAIT가 설정되었습니다."

따라서 낙관적인 잠금을 사용할 수 없고 트랜잭션을 단축할 수 없는 경우 select_for_update에서 nowait=true를 설정할 수 있으며 가정이 맞으면 많은 오류가 발생합니다.여기서는 교착 상태의 장애를 포착하여 백오프 전략으로 재시도할 수 있습니다.이것은 모든 사람들이 경매 물건이나 짧은 시간 안에 표를 예매하는 것과 같이 같은 것에 글을 쓰려고 한다는 가정에 바탕을 두고 있다.그렇지 않은 경우 교착 상태를 일반화하기 위해 DB 설계를 약간 변경하는 것을 고려하십시오.

언급URL : https://stackoverflow.com/questions/54588123/django-mariadb-mysql-does-select-for-update-lock-rows-from-subqueries-causin

반응형