programing

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

shortcode 2022. 9. 25. 15:05
반응형

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

쿼리:

SELECT COUNT(online.account_id) cnt from online;

""을 실행하여 할 수 .show processlist.

MySQL에서 잠금을 유발하지 않는 선택문을 만들 수 있는 문법이 있습니까?

그리고 MySQL 슬레이브 데이터베이스에 있다는 것을 위에서 언급하는 것을 잊었습니다.

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

오류 '이진 로그가 불가능합니다.메시지:InnoDB의 트랜잭션 수준 'READ-UNCOMMITED'는 쿼리의 binlog 모드 'STATEN'에 안전하지 않습니다.

그럼 호환성이 있는 방법이 있을까요?

"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 ;

테이블이 InnoDB인 경우 http://dev.mysql.com/doc/refman/5.1/en/innodb-consistent-read.html를 참조하십시오.innodb_display_for_binlog 옵션이 설정되고 트랜잭션 분리 수준이 SERIABLE로 설정되지 않은 경우 SELECT에 대해 "FOR UPDATE 또는 LOCK IN SARE MODE를 지정하지 않음"을 사용합니다.따라서 선택한 테이블에서 읽은 행에는 잠금이 설정되지 않습니다."

사용하다

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED.

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

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

링크된 문서에서 인용: 트랜잭션 특성 설정(위와 같이)...

SESSION 키워드 또는 GLOBAL 키워드가 없는 경우:

  • 이 문장은 세션 내에서 실행되는 다음 단일 트랜잭션에만 적용됩니다.

  • 후속 트랜잭션은 지정된 특성의 세션 값을 사용하여 돌아갑니다.

  • 트랜잭션에서는 해당 문장이 허용되지 않습니다.

MySQL 설명서의 이 페이지를 읽어보실 수 있습니다.테이블 잠그는 방법은 테이블 유형에 따라 달라집니다.

MyISAM은 테이블 잠금을 사용하여 매우 빠른 읽기 속도를 달성하지만 UPDATE 스테이트먼트가 대기하고 있는 경우 이후 SELECTS는 UPDATE 뒤에 대기합니다.

InnoDB 테이블은 행 수준의 잠금을 사용하여 UPDATE 뒤에 테이블 전체를 잠글 수 없습니다.InnoDB에는 다른 종류의 잠금 문제가 있지만, 고객님의 요구에 맞는 잠금 문제가 있을 수 있습니다.

mysql에서 더티 읽기를 활성화하는 또 다른 방법은 힌트를 추가하는 것입니다: 공유 모드에서 잠금

SELECT * FROM TABLE_NAME LOCK IN SHARE MODE; 

테이블 유형에 따라 잠금이 다르게 수행되지만 SELECT 카운트도 달라집니다.MyISAM 테이블의 경우 단순 SELECT 카운트(*) FROM 테이블은 메타데이터에 액세스하여 레코드 카운트를 가져오기 때문에 테이블을 잠글 수 없습니다.Innodb는 기록을 세기 위해 스냅숏에서 테이블을 잡아야 하기 때문에 시간이 더 걸리겠지만 잠기지는 않을 것입니다.

적어도 concurrent_insert는 1(기본값)로 설정해야 합니다.그러면 테이블이 채워질 데이터 파일에 "갭"이 없으면 파일에 삽입이 추가되고 MyISAM 테이블과 동시에 SELECT 및 INSERT가 발생할 수 있습니다.레코드를 삭제하면 데이터 파일에 공백이 생기므로 나중에 삽입 및 업데이트로 채워질 수 있습니다.

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

요컨대, 테이블에 업데이트, 삽입, 선택이 많으면 InnoDB로 해야 합니다.단, 시스템에서 테이블 유형을 자유롭게 혼합할 수 있습니다.

참조에서:

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

SELECT는 보통 InnoDB 테이블에서 사용자가 신경 쓰는 잠금을 수행하지 않습니다.기본 트랜잭션 분리 수준은 가 물건을 잠그지 않음을 선택하는 것을 의미합니다.

물론 경합은 여전히 일어난다.

다음은 MyISAM IF(중요)를 사용하는 다른 사용자에게 적합한 대체 프로그래밍 솔루션입니다. 쿼리 도중 업데이트가 이루어졌어도 상관없습니다.MyISAM에 의해 테이블레벨 잠금이 발생할 수 있습니다.특히 잠기는 업데이트가 보류 중인 경우 이 업데이트 뒤에 있는 다른 선택 쿼리도 잠깁니다.

따라서 이 방법은 잠금을 방지하는 것이 아니라 매우 짧은 시간 내에 응답을 필요로 하는 웹 사이트를 걸지 않도록 많은 작은 잠금을 만들 수 있습니다.

여기서의 아이디어는 인덱스를 기반으로 한 범위를 빠르게 파악한 다음 해당 쿼리에서만 매칭을 수행하므로 더 작은 배치로 이루어집니다.그런 다음 목록을 다음 범위로 이동하여 일치 여부를 확인합니다.

예를 들어 Perl에서는 의사 코드 비트를 사용하여 하이에서 로우로 이동합니다.


# object_id must be an index so it's fast
# First get the range of object_id, as it may not start from 0 to reduce empty queries later on.

my ( $first_id, $last_id ) = $db->db_query_array(
  sql => q{ SELECT MIN(object_id), MAX(object_id) FROM mytable }
);

my $keep_running = 1;
my $step_size    = 1000;
my $next_id      = $last_id;

while( $keep_running ) {

    my $sql = q{ 
SELECT object_id, created, status FROM 
    ( SELECT object_id, created, status FROM mytable AS is1 WHERE is1.object_id <= ? ORDER BY is1.object_id DESC LIMIT ? ) AS is2
WHERE status='live' ORDER BY object_id DESC 
};  

    my $sth = $db->db_query( sql => $sql, args => [ $step_size, $next_id ] );

    while( my ($object_id, $created, $status ) = $sth->fetchrow_array() ) {

        $last_id = $object_id;
        
        ## do your stuff

    }

    if( !$last_id ) {
        $next_id -= $step_size; # There weren't any matched in the range we grabbed
    } else {
        $next_id = $last_id - 1; # There were some, so we'll start from that.
    }

    $keep_running = 0 if $next_id < 1 || $next_id < $first_id;
    
}



언급URL : https://stackoverflow.com/questions/917640/any-way-to-select-without-causing-locking-in-mysql

반응형