MySQL에서 잠금을 발생시키지 않고 선택할 수있는 방법이 있습니까?


126

질문:

SELECT COUNT(online.account_id) cnt from online;

그러나 온라인 테이블도 이벤트에 의해 수정되므로 자주 실행하여 lock을 볼 수 있습니다 show processlist.

MySQL에서 select 문으로 인해 잠금이 발생하지 않도록하는 문법이 있습니까?

그리고 위에서 MySQL 슬레이브 데이터베이스에 있다는 것을 잊어 버렸습니다.

my.cnf:transaction-isolation = READ-UNCOMMITTED 슬레이브에 추가하면 오류가 발생합니다.

오류 '이진 로깅이 불가능합니다. 메시지 : InnoDB의 트랜잭션 레벨 'READ-UNCOMMITTED'는 쿼리의 binlog 모드 'STATEMENT'에 안전하지 않습니다.

그렇다면 호환 가능한 방법이 있습니까?


3
이 질문에 직면하고 테이블의 잠금으로 어려움을 겪고있는 다른 사람들을 위해 : mySQL이 내부적으로 잠금을 사용하는 방법은 스토리지 엔진에 달려 있습니다. 아래 @zombat의 답변을 읽으십시오.
Simon Forsberg

답변:


169

"MYSQL WITH NOLOCK"이라는 제목의 기사를 찾았습니다.

https://web.archive.org/web/20100814144042/http://sqldba.org/articles/22-mysql-with-nolock.aspx

MS SQL Server에서는 다음을 수행합니다.

SELECT * FROM TABLE_NAME WITH (nolock)

MYSQL에 해당하는 것은

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
SELECT * FROM TABLE_NAME ;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ ;

편집하다

Michael Mior 는 (의견에서) 다음을 제안했습니다.

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
SELECT * FROM TABLE_NAME ;
COMMIT ;

54
미래 독자들에게 당신이 제거 SESSION하고 싶을 수 있으므로 트랜잭션 레벨이 다음 트랜잭션에만 적용되도록주의하십시오. 그런 다음 위의 세 번째 문을로 바꿉니다 COMMIT. 이 경우 이것은 엉망이지만 트랜잭션을 끝내고 기본 격리 수준으로 재설정하는 부작용이 있습니다.
Michael Mior

3
참고로, 그 링크는 죽었습니다 ... :(
longda

5
죄송합니다. InnoDB와 MyISAM의 중요한 차이점은 여기에 언급하지 않았습니다. 위의 @omg에서 언급했듯이 이것은 InnoDB에서는 작동하지만 MyISAM 테이블에서는 작동하지 않습니다.
Simon Forsberg

4
@Craig MyISAM이 SELECT 쿼리 중에 READ 잠금을 발행하지 않는 것은 확실히 부정확합니다. 잠금이 있으며 InnoDB와 반대되는 잠금은 테이블 잠금이므로 요청 된 모든 WRITE 잠금 실행 중에 모든 후속 쿼리를 차단합니다 . 원래 질문은 격리 수준이 너무의 MyISAM을 위해 존재하지 않는다 불구하고 InnoDB에 대한 것으로 보인다 - 에 대한 문서 SET TRANSACTION 상태 : ".이 문은 InnoDB 테이블에 작업에 사용되는 트랜잭션 격리 수준을 설정합니다"
syneticon-dj

1
인정한 포인트. :-) MyISAM 대 InnoDB의 잠금 동작을 실제로 언급하려고했습니다. 이러한 격리 수준 기반 솔루션은 트랜잭션이 아닌 MyISAM에는 적용되지 않으므로 간단한 테이블 잠금을 사용 합니다 . MyISAM UPDATE 및 DELETE는 테이블 잠금이 지워질 때까지 기다려야하므로 쓰기 요청이 완료 될 때까지 이후의 SELECT 큐가 쓰기 요청 뒤에 대기합니다. MyISAM에는 "더러운 읽기"가 없으며 대부분의 쓰기가 읽기와 동시에 발생할 수있는 방법이 없으므로 "MyISAM을 해결하지 못합니다." 나는 그것이 내가 받고있는 것이라고 생각합니다. :-)
Craig

24

테이블이 InnoDB 인 경우 http://dev.mysql.com/doc/refman/5.1/en/innodb-consistent-read.html을 참조 하십시오. SELECT에 대해 일관된 읽기 (비 잠금 모드)를 사용합니다. innodb_locks_unsafe_for_binlog 옵션이 설정되고 트랜잭션의 격리 레벨이 SERIALIZABLE로 설정되지 않은 경우 FOR UPDATE 또는 LOCK IN SHARE MODE를 지정하지 마십시오. 따라서 선택된 테이블에서 읽은 행에 잠금이 설정되지 않습니다 ".


16

사용하다

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED.

버전 5.0 문서는 여기에 있습니다 .

버전 5.1 문서가 있습니다 .


2
고마워요 PHP 프로그램에서이 문장을 사용할 것입니다. 쿼리가 완료되면 TRANSACTION ISOLATION LEVEL을 자동으로 재설정하는 것이 가장 좋습니다
omg

14

MySQL 매뉴얼 의이 페이지 를 읽을 수 있습니다 . 테이블이 잠기는 방법은 테이블 유형에 따라 다릅니다.

MyISAM은 테이블 잠금을 사용하여 매우 빠른 읽기 속도를 달성하지만 UPDATE 문이 대기중인 경우 향후 SELECTS가 UPDATE 뒤에 대기합니다.

InnoDB 테이블은 행 수준 잠금을 사용하므로 UPDATE 뒤에 전체 테이블이 잠기지 않습니다. InnoDB와 관련된 다른 종류의 잠금 문제가 있지만 필요에 맞게 찾을 수 있습니다.


1
"SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED"가 MyISAM 테이블에서 작동합니까?
omg

5
MyISAM 테이블은 어떤 형태의 트랜잭션도 지원하지 않습니다. 트랜잭션 쿼리는 MyISAM 테이블에서 실행되므로 위에서 언급 한 쿼리는 실행되지만 효과는 없습니다.
zombat

1
그런 다음 MyISAM의 경우 SELECTS가 대기하지 않도록하려면 어떻게해야합니까?
omg

6
MyISAM의 경우 SELECTS가 대기하지 않도록하려면 어떻게해야합니까? innodb로 전환하십시오. MyISAM은 모든 쿼리에 대해 테이블 ​​수준 잠금을 사용합니다. 그것은 큰 결함입니다.
Frank Farmer

2

테이블 유형에 따라 잠금은 다르게 수행되지만 SELECT 횟수도 달라집니다. MyISAM 테이블의 경우 간단한 SELECT count (*) FROM 테이블은 메타 데이터에 액세스하여 레코드 수를 가져 오기 때문에 테이블을 잠그면 안됩니다. Innodb는 레코드를 계산하기 위해 스냅 샷에서 테이블을 가져와야하므로 시간이 오래 걸리지 만 잠금이 발생하지는 않습니다.

적어도 synchronize_insert가 1 (기본값)로 설정되어 있어야합니다. 그런 다음 테이블에 채울 데이터 파일에 "갭"이 없으면 삽입이 파일에 추가되고 SELECT 및 INSERT가 MyISAM 테이블과 동시에 발생할 수 있습니다. 레코드를 삭제하면 데이터 파일에 "갭"이 생겨 향후 삽입 및 업데이트로 채워집니다.

레코드를 거의 삭제하지 않으면 동시 _ 삽입을 2로 설정할 수 있으며 삽입은 항상 데이터 파일 끝에 추가됩니다. 그러면 선택 및 삽입이 동시에 발생할 수 있지만 삭제하는 레코드 수에 관계없이 데이터 파일은 더 작아지지 않습니다 (모든 레코드 제외).

결론적으로, 테이블에 많은 업데이트, 삽입 및 선택이있는 경우 InnoDB로 만들어야합니다. 시스템에서 테이블 유형을 자유롭게 혼합 할 수 있습니다.


1

mysql에서 더티 읽기를 활성화하는 또 다른 방법은 힌트 추가입니다. LOCK IN SHARE MODE

SELECT * FROM TABLE_NAME LOCK IN SHARE MODE; 

"자동 커밋이 1로 설정되어 있으면 LOCK IN SHARE MODE 및 FOR UPDATE 절이 적용되지 않습니다." ... 및 autocommit = 1이 기본값입니다
Martin Zvarík

0

에서 참조 :

LOCK TABLES를 사용하여 테이블 잠금을 명시 적으로 확보 한 경우 테이블을 잠근 상태에서 다른 세션이 동시 삽입을 수행 할 수 있도록 READ 잠금 대신 READ LOCAL 잠금을 요청할 수 있습니다.


0

일반적으로 SELECT는 InnoDB 테이블에서 관심있는 잠금을 수행하지 않습니다. 기본 트랜잭션 격리 수준은 선택 항목을 잠그지 않음을 의미합니다.

물론 경합은 여전히 ​​발생합니다.


1
나는이 게시물이 오래되었다는 것을 알고 있지만이 답변은 너무 일반적이며 때로는 사실입니다. dev.mysql.com/doc/refman/5.0/en/innodb-locks-set.html을 참조하십시오 . 잠금 가장 확실하게 하는 격리 수준에 따라 읽기에 대한 인수했다. 특히이 경우 포스터는 복제 된 데이터베이스를 처리하고 show processlist실제로 잠금을 보는 데 사용할 수 있다고 명시 적으로 언급했습니다 . 따라서 실제로 잠금이 있다고 가정하는 것이 안전합니다.
Craig

1
답은 항상 사실입니다. 물론 일부 잠금이 있습니다-innodb 내부에 사용되는 일부 내부 뮤텍스 (예 : innodb 버퍼 풀 뮤텍스). 대부분의 사용자는 이러한 잠금을 신경 쓰지 않거나 알지 못하며 일반적으로 16G 버퍼 풀이 있고 다른 스레드에서 "테이블 삭제"를 수행하는 경우와 같이 DDL 작업 중에 만 충돌합니다. 그러나 기본적으로 행 잠금은 사용하지 않습니다. 그게 내 뜻이야 대답은 꽤 모호했다.
MarkR

1
항상 ? 트랜잭션 격리 수준이 직렬화 가능으로 설정되거나 select 문이 LOCK IN SHARE MODE를 사용하고 자동 커밋이 비활성화 된 경우 어떻게됩니까? 많은 (대부분 / 모두의) 데이터베이스 서버가 현재 진정한 직렬화 대신 기본적으로 스냅 샷 격리를 사용하지만 직렬화 가능한 읽기를 강제하는 경우가 가끔 정당화되지 않습니까? 그러나 원격으로 정상적인 모든 경우에 MySQL의 기본 조건으로 인해 다른 스레드에 영향을 미치는 읽기 잠금이 발생하지 않으므로 문제가 있다고 걱정하지 마십시오. 다운 보트 BTW를 취소하려고했습니다. 미안 ...
Craig

3
나는 "정상적으로하지 말라"고 말했다. 나는 당신이 정상적인 선택을하고 (업데이트 또는 잠금 모드 공유 모드없이) 기본 트랜잭션 격리 수준을 사용한다는 것을 의미했습니다. 격리 수준을 변경하는 몇 가지 유효한 경우가 있지만 세션별로 기본 설정을 수행하지는 않습니다.
MarkR
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.