충격! 하나의 SQL 문에 너무 많은 잠금이 있습니다 ...
권장(무료): SQL 튜토리얼
Gap 잠금과 행 잠금을 함께 사용하면 잠금 대기가 발생할지 여부를 판단하는 데 실수하기 쉽습니다.
간격 잠금은 반복 읽기 격리 수준에서만 효과적이므로 이 문서에서는 기본적으로 반복 읽기를 사용합니다.
잠금 규칙
- 원칙 1
잠금의 기본 단위는 열림과 닫힘 간격인 넥스트 키 잠금입니다. - 원칙 2
검색 과정에서 접근한 객체만 잠깁니다. - 최적화 1
인덱스에 대한 동등한 쿼리의 경우 고유 인덱스를 잠그면 다음 키 잠금이 행 잠금으로 변질됩니다. - 최적화 2
인덱스에 대한 동일 쿼리의 경우 오른쪽으로 순회하고 마지막 값이 동일 조건을 충족하지 않으면 다음 키 잠금이 간격 잠금으로 퇴화됩니다. - 버그
고유 인덱스에 대한 범위 쿼리는 조건을 충족하지 않는 첫 번째 값에 액세스합니다.
데이터 준비
테이블 이름: t
새 데이터: (0,0,0),(5,5,5),(10,10,10),(15,15,15), ( 20,20,20),(25,25,25)
다음 예는 기본적으로 그림 설명을 동반하므로 원고와 대조하여 읽어 보시기 바랍니다. 일부 예는 "세 가지 견해를 망칠" 수 있으므로 다음을 권장합니다. 기사를 읽은 후 직접 연습해 보세요.
Case
동일값 쿼리 간격 잠금
동일값 쿼리 간격 잠금
테이블 t에는 id=7이 없으므로 원칙 1에 따라 잠금 단위는 다음- 키 잠금, 따라서 세션 A의 잠금 범위 (5,10]
동시에 최적화 2에 따르면 동등한 쿼리(id=7)이지만 id=10이 만족되지 않으면 다음 키 lock은 gap lock으로 변질되므로 최종 잠금 범위는 (5,10)
따라서 세션 B가 id=8인 레코드를 이 gap에 삽입하면 잠기지만 세션 C는 다음과 같이 행을 수정할 수 있습니다. id=10.
비고유 인덱스에 해당합니다. Lock
비고유 인덱스에만 추가되는 잠금
세션 A는 c=5에 읽기 잠금을 추가해야 합니다. 인덱스 c의 행
원칙 1에 따르면 잠금 단위는 next-key 잠금이므로 (0,5]에 next-key 잠금을 추가합니다.
c는 일반 인덱스 이므로 레코드 c=5 에만 액세스할 수 없습니다. 즉시 중지, 오른쪽으로 이동하고 c=10을 찾은 경우에만 포기해야 합니다. 원칙 2에 따르면 액세스된 모든 항목은 잠겨 있어야 하므로 (5,10]에 다음 키 잠금을 추가합니다. 동시에 최적화 2: 동등성 판단을 충족하고 오른쪽으로 이동하며 마지막 값은 c=5의 동등성 조건을 충족하지 않으므로 간격 잠금(5,10)
원칙 2에 따르면, 액세스된 객체는 잠깁니다. 이 쿼리는 커버링 인덱스를 사용하고 기본 키 인덱스에 액세스할 필요가 없으므로 기본 키 인덱스에 잠금이 추가되지 않으므로 세션 B의 업데이트 문이 실행될 수 있습니다. C가 (7,7,7)을 삽입하려고 하면 세션 A의 간격 잠금(5,10)에 의해 잠깁니다. 이 예에서 공유 모드의 잠금은 포함 인덱스만 잠그지만 업데이트를 위해 실행하면 시스템은 다음에 데이터를 업데이트하려고 한다고 생각하므로 기본 키 인덱스의 조건을 충족하는 행에 행 잠금을 추가합니다.
이 예는 다음과 같습니다. 동시에 인덱스에 잠금이 추가된다는 점을 설명합니다. 공유 모드에서 잠금을 사용하여 행에 읽기 잠금을 추가하여 데이터가 업데이트되는 것을 방지하려면 우회해야 한다는 지침이 제공됩니다. 커버링 인덱스의 최적화. 인덱스에 존재하지 않는 필드를 추가합니다. 예를 들어 공유 모드에서 c=5 잠금에서 d를 선택하도록 세션 A의 쿼리 문을 변경하면 효과를 직접 확인할 수 있습니다. 3 기본 키 인덱스 범위 잠금
Range 쿼리.
다음 두 쿼리 문은 동일한 잠금 범위를 갖나요? mysql> select * from t where id=10
mysql> * from t where id>=10 and id<11 for update;id가 int 유형으로 정의되므로 이 두 문장이 동일하다고 생각할 수도 있습니다. 사실, 그들은 완전히 동일하지 않습니다.
논리적으로 이 두 검색 문은 확실히 동일하지만 잠금 규칙은 다릅니다. 이제 세션 A가 두 번째 쿼리 문을 실행하여 잠금 효과를 살펴보겠습니다.
그림 3 기본 키 인덱스의 범위 쿼리에 대한 잠금
이제 앞서 언급한 잠금 규칙을 사용하여 세션 A에 어떤 잠금이 추가될지 분석해 보겠습니다.
따라서 이때 세션 A의 잠금 범위는 기본 키 인덱스, 행 잠금 id=10 및 다음 키 잠금(10,15]입니다. 이를 통해 세션 B와 세션 C의 결과를 이해할 수 있습니다.
여기서 주목해야 할 점은 첫 번째 세션 A에서 id=10인 행을 찾으면 등가 쿼리로 판단하고, id=15까지 오른쪽으로 스캔하면 범위로 판단한다는 것입니다. 쿼리
.범위 쿼리 잠금을 다시 보면 사례 3과 비교할 수 있습니다.
고유하지 않은 인덱스 범위 잠금
session_1 | session_2 | session_3 |
---|---|---|
begin; t에서 *를 선택하세요 여기서 업데이트의 경우 c>=10 및 c<11입니다. | update t set d=d+1 여기서 c=15;(차단됨) | |
session1 c=10</을 사용하는 경우 code>를 사용하여 처음으로 레코드를 찾으려면 인덱스 c에 <code>(5,10] next-key lock 이 추가됩니다. | c는 | 고유하지 않은 인덱스입니다. 최적화 규칙은 없습니다. 즉, 행 잠금 | 으로 변질되지 않습니다. 따라서 session1은 최종적으로 c
따라서 결과 관점에서 sesson2가 (8,8,8)의 삽입 문을 삽입하려고 하면 차단됩니다. | 고유하지 않은 인덱스는 c=15로 스캔되어야 합니다. 계속해서 뒤로 이동할 필요는 없습니다.
c=10
定位记录时,索引c加了(5,10] next-key lock
- c是非唯一索引,无优化规则,即不会退变为行锁
- 因此最终sesion1加锁为c的
(5,10]
和(10,15]
next-key lock。
所以从结果上来看,sesson2要插入(8,8,8)的这个insert语句时就被阻塞。
非唯一索引要扫到c=15,才知道无需继续往后遍历。
唯一索引范围锁bug
前四案例用到两个原则和两个优化,再看加锁规则bug案例。
session_1 | session_2 | session_3 |
---|---|---|
begin; select * from t where id>10 and id<=15 for update; | ||
update t set d=d+1 where id=20;(阻塞) | ||
insert into t values(16,16,16);(阻塞) |
session1是范围查询
- 按原则1,索引id只加
(10,15] next-key lock
,因为id是唯一键,所以循环判断到id=15
这行就该停止遍历。
但实现上,InnoDB会继续扫描到第一个不满足条件的行,即id=20
,且由于这是范围扫描,因此id上的(15,20] next-key lock
也会被锁。
所以session2要更新id=20这行会被阻塞。
session3要插入id=16,也会被阻塞。
按理说锁住id=20这行没必要,因为唯一索引扫描到id=15即可确定不用继续遍历。但实现上还是这么做了,可能是个bug。
非唯一索引上存在"等值"的例子
为更好地说明“间隙”概念。
插入记录7
新插入的这一行c=10,即现在表里有两个c=10。那么,这时索引c上的间隙是什么状态了呢?
由于非唯一索引上包含主键的值,所以不可能存在“相同”两行。
但现在虽然有两个c=10,它们的主键值id却不同,因此这两个c=10记录之间也有间隙。
看如下案例。
6
delete加锁逻辑类似select ... for update
session_1
begin; | ||
---|---|---|
업데이트 t | 세트 d =d+1 여기서 id=20;(blocking) |
|
따라서 session2가 id=20 행을 업데이트하려는 경우 차단됩니다. |
6 | 삭제 잠금 논리는 |
---|---|
session_2 session_3 |
|
c=10 |
session1의 삭제 문에 제한 2가 추가되었습니다. 실제로 테이블 t에는 c=10인 레코드가 2개만 있으므로 제한 2를 추가하든 안 하든 삭제 효과는 동일하지만 잠금 효과는 다릅니다. Case 6의 결과와는 다르게 세션 B의 insert 문이 통과된 것을 확인할 수 있습니다.
이것은 Case 7의 삭제 문이 명확하게 제한 2의 제한을 추가했기 때문에 라인(c=10, id=30)으로 이동한 후 이미 조건을 충족하는 두 개의 명령문이 있고 루프가 종료되기 때문입니다.
따라서 인덱스 c의 잠금 범위는 아래 그림과 같이 (c=5, id=5)에서 (c=10, id=30)까지 전면 열림 및 후면 닫힘 간격이 됩니다.
제한 2
의 잠금 효과를 보면 (c=10, id=30) 이후의 간격이 잠금 범위에 있지 않으므로 c=12를 삽입하는 insert 문이 성공적으로 실행될 수 있습니다.
우리 실습에서 이 예의 중요한 의미는 데이터를 삭제할 때 제한을 추가하려고 시도하는 것입니다. 이는 삭제된 데이터의 수를 제어하여 작업을 보다 안전하게 할 뿐만 아니라 잠금 범위를 줄여줍니다.
교착상태 예시
이전 예시에서는 분석할 때 next-key lock의 로직에 따라 분석했는데, 이렇게 분석하는 것이 더 편리하기 때문입니다. 마지막으로 설명하기 위해 또 다른 사례를 살펴보겠습니다. 다음 키 잠금은 실제로 간격 잠금과 행 잠금의 합계 결과입니다.
이런 컨셉이 처음에도 언급되지 않았는지 궁금하시죠? 걱정하지 마세요. 다음 예를 먼저 살펴보겠습니다.
케이스 8
session A의 작업 순서 A. 트랜잭션 시작 후 쿼리 문을 실행하고 공유 모드에서 잠금을 추가한 후 next-key를 추가합니다. lock(인덱스 c의 5,10] 및 갭 잠금(10,15);
세션 B의 업데이트 문은 또한 인덱스 c에 다음 키 잠금(5,10]을 추가하고 잠금 대기를 입력해야 합니다.
그런 다음 세션 A는 (8,8,8)을 삽입해야 합니다. 이 줄은 세션 B의 갭 잠금으로 인해 잠겨 있습니다. 교착 상태로 인해 InnoDB는 세션 B를 롤백합니다.
세션의 다음 키 잠금이 아닌가? B가 성공적으로 적용되었나요?
실제로 세션 B의 "다음 키 잠금 추가(5,10]" 작업은 실제로 두 단계로 나누어집니다. 먼저 (5,10)의 간격 잠금을 추가합니다. 잠금이 성공하면 c=10을 추가합니다. 이때 행 잠금이 잠깁니다. 즉, 다음 키 잠금을 사용하여 잠금 규칙을 분석할 수 있지만 특정 실행 중에는 갭 잠금으로 나누어야 하며 행 잠금은 2단계로 실행됩니다.요약
모든 경우는 반복 읽기에서 확인됩니다. 모든 잠긴 리소스는 2단계 잠금 프로토콜을 따릅니다. 마지막 경우에는 실제로 next-key 잠금이 gap 잠금과 row 잠금으로 구현된다는 것을 확실히 알 수 있는데, 읽기 커밋 격리 수준으로 전환하면 gap 잠금 부분이 제거되어 이해하기 쉽습니다. 그 과정에서 행 잠금 부분만 남습니다. 읽기 커밋 격리 수준 아래에는 또 다른 최적화가 있습니다. 즉, 문 실행 중에 행 잠금이 추가되는 것입니다. "조건을 충족하지 않는 행"에서는 트랜잭션이 커밋될 때까지 기다리지 않고 직접 해제해야 합니다. 읽기-커밋 격리 수준에서는 잠금 범위가 작고 잠금 시간이 짧아서 많은 기업에서도 사용합니다.
SQL
무료 칼럼~~을 참조하세요.
위 내용은 충격! 하나의 SQL 문에 너무 많은 잠금이 있습니다 ...의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











HQL과 SQL은 Hibernate 프레임워크에서 비교됩니다. HQL(1. 객체 지향 구문, 2. 데이터베이스 독립적 쿼리, 3. 유형 안전성), SQL은 데이터베이스를 직접 운영합니다(1. 데이터베이스 독립적 표준, 2. 복잡한 실행 파일) 쿼리 및 데이터 조작).

"OracleSQL의 나눗셈 연산 사용법" OracleSQL에서 나눗셈 연산은 일반적인 수학 연산 중 하나입니다. 데이터 쿼리 및 처리 중에 나누기 작업은 필드 간의 비율을 계산하거나 특정 값 간의 논리적 관계를 도출하는 데 도움이 될 수 있습니다. 이 문서에서는 OracleSQL의 나누기 작업 사용법을 소개하고 구체적인 코드 예제를 제공합니다. 1. OracleSQL의 두 가지 분할 연산 방식 OracleSQL에서는 두 가지 방식으로 분할 연산을 수행할 수 있습니다.

Oracle과 DB2는 일반적으로 사용되는 관계형 데이터베이스 관리 시스템으로, 각각 고유한 SQL 구문과 특성을 가지고 있습니다. 이 기사에서는 Oracle과 DB2의 SQL 구문을 비교 및 차이점을 설명하고 구체적인 코드 예제를 제공합니다. 데이터베이스 연결 Oracle에서는 다음 문을 사용하여 데이터베이스에 연결합니다. CONNECTusername/password@database DB2에서 데이터베이스에 연결하는 문은 다음과 같습니다. CONNECTTOdataba

MyBatis 동적 SQL 태그 해석: Set 태그 사용법에 대한 자세한 설명 MyBatis는 풍부한 동적 SQL 태그를 제공하고 데이터베이스 작업 명령문을 유연하게 구성할 수 있는 탁월한 지속성 계층 프레임워크입니다. 그 중 Set 태그는 업데이트 작업에서 매우 일반적으로 사용되는 UPDATE 문에서 SET 절을 생성하는 데 사용됩니다. 이 기사에서는 MyBatis에서 Set 태그의 사용법을 자세히 설명하고 특정 코드 예제를 통해 해당 기능을 보여줍니다. Set 태그란 무엇입니까? Set 태그는 MyBati에서 사용됩니다.

SQL에서 ID란 무엇입니까? SQL에서 ID는 자동 증가 숫자를 생성하는 데 사용되는 특수 데이터 유형으로, 테이블의 각 데이터 행을 고유하게 식별하는 데 사용됩니다. ID 열은 일반적으로 기본 키 열과 함께 사용되어 각 레코드에 고유한 식별자가 있는지 확인합니다. 이 문서에서는 Identity를 사용하는 방법과 몇 가지 실제 코드 예제를 자세히 설명합니다. Identity를 사용하는 기본 방법은 테이블을 생성할 때 Identit을 사용하는 것입니다.

해결 방법: 1. 로그인한 사용자에게 데이터베이스에 액세스하거나 운영할 수 있는 충분한 권한이 있는지 확인하고 해당 사용자에게 올바른 권한이 있는지 확인하십시오. 2. SQL Server 서비스 계정에 지정된 파일에 액세스할 수 있는 권한이 있는지 확인하십시오. 3. 지정된 데이터베이스 파일이 다른 프로세스에 의해 열렸거나 잠겼는지 확인하고 파일을 닫거나 해제한 후 쿼리를 다시 실행하십시오. .관리자로 Management Studio를 실행해 보세요.

데이터베이스 기술 경쟁: Oracle과 SQL의 차이점은 무엇입니까? 데이터베이스 분야에서 Oracle과 SQL Server는 매우 존경받는 관계형 데이터베이스 관리 시스템입니다. 둘 다 관계형 데이터베이스 범주에 속하지만 둘 사이에는 많은 차이점이 있습니다. 이 기사에서는 Oracle과 SQL Server의 차이점과 실제 애플리케이션에서의 기능 및 장점을 자세히 살펴보겠습니다. 우선, Oracle과 SQL Server 사이에는 구문에 차이가 있습니다.

Apple 휴대폰은 최근 사람들이 가장 많이 선택하는 휴대폰이지만, 온라인에서 잠겨 있는 Apple 휴대폰과 잠금 해제된 Apple 휴대폰의 차이점에 대해 토론하는 사람들을 종종 볼 수 있으며, 어떤 것을 사야 할지 얽혀 있습니다. 오늘 Chen Siqi는 잠긴 iPhone과 잠금 해제된 iPhone의 차이점을 공유하고 문제 해결에 도움을 드릴 것입니다. 사실 외관이나 기능면에서는 둘 사이에 큰 차이가 없습니다. 핵심은 가격과 용도에 있습니다. 잠금 버전과 잠금 해제 버전은 무엇인가요? 잠금 제한이 없는 iPhone은 이동통신사에 의해 제한되지 않으며 모든 이동통신사의 SIM 카드를 정상적으로 사용할 수 있다는 의미입니다. 잠금 버전은 네트워크 잠금 기능이 있어 지정된 사업자가 제공한 SIM 카드만 사용할 수 있고 다른 SIM 카드는 사용할 수 없음을 의미합니다. 실제로 언락된 애플폰은 모바일을 사용할 수 있고,
