MySQL 데이터베이스 : SQL 문의 실행 프로세스

1. 클라이언트의 MySQL 드라이버 :

시스템이 MySQL 데이터베이스와 통신하기 전에 데이터베이스와의 연결을 설정해야합니다.이 기능은 MySQL 드라이버의 맨 아래 계층에서 수행합니다. 연결이 설정되면 SQL 문만 보내서 CRUD를 실행하면됩니다. . 아래 그림과 같이:

하나의 SQL 요청은 하나의 연결을 설정하고 여러 요청은 여러 연결을 설정합니다. 시스템이 tomcat 컨테이너에 배치되어 있다고 가정하면 tomcat은 여러 요청을 동시에 처리 할 수 ​​있으므로 여러 요청이 여러 연결을 설정 한 다음 사용 후에 닫힙니다.이 문제는 어떻게됩니까?? Java 시스템은 MySQL 드라이버를 통해 MySQL 데이터베이스에 연결할 때 TCP / IP 프로토콜을 기반으로하기 때문에 각 요청이 연결을 생성하고 파괴하는 경우 이러한 빈번한 연결 생성 및 파괴는 필연적으로 시스템 성능을 크게 저하시킵니다. .

위의 문제점을 해결하기 위해 연결 풀을 통해 일정 수의 연결 스레드를 유지하기 위해 "풀링"이라는 개념을 채택하고 있습니다. 연결이 필요한 경우 스레드 풀에서 직접 가져 와서 사용 후 스레드 풀. 스레드 풀은 지속적으로 스레드를 생성하고 파괴하는 오버 헤드를 크게 줄여 주며, 연결 생성 및 소멸과 스레드 풀이 이러한 연결을 유지하는 방법에 대해 신경 쓸 필요가 없습니다. 일반적인 데이터베이스 연결 풀은 Druid, C3P0, DBCP입니다.

 

2. MySql 아키텍처의 서버 계층 :

서버의 MySQL 데이터베이스에서 SQL 문의 실행 단계를 소개하기 전에 먼저 MySQL의 전체 구조를 이해해 보겠습니다.

위의 그림이 명확하지 않으면 다음 그림을 다시 볼 수 있습니다.

위의 아키텍처 다이어그램에서 서버 계층은 주로 커넥터, 쿼리 캐시, 리졸버 / 분석기, 옵티 마이저 및 실행기로 구성되어 있음 을 알 수 있으며 이러한 부분 은 주로 아래에서 설명합니다.

1. 커넥터 :

클라이언트가 데이터베이스를 운영하고자 할 때 전제는 데이터베이스와의 연결을 설정하는 것이며 커넥터는 클라이언트와의 연결을 설정하고 권한을 얻고 연결을 유지 및 관리하는 데 사용됩니다.

(1) 연결 방법 :

MySQL은 짧은 연결과 긴 연결을 모두 지원합니다. 짧은 연결은 작업이 완료된 후 즉시 닫히는 것입니다. 긴 연결은 열린 상태로 유지하여 연결을 만들고 해제하는 서버의 소비를 줄일 수 있으며이 연결은 후속 프로그램 액세스 중에도 사용할 수 있습니다.

(2) 연결 풀 :

클라이언트의 연결 풀과 마찬가지로 잦은 연결 생성 및 파괴로 인한 불필요한 성능 손실을 줄이기 위해 여기서 "풀링"개념을 채택하여 데이터베이스 연결 풀을 통해 연결을 관리합니다. 일반적으로 연결 풀에서 긴 연결을 사용 합니다 (예 : druid, c3p0, dbcp 등).

2. 쿼리 캐시 :

MySQL 캐시는 기본적으로 꺼져 있으므로 캐시 사용을 권장하지 않으며  쿼리 캐시의 전체 기능은 MySQL 8.0 버전 에서 직접 삭제됩니다

(1) MySql이 기본적으로 캐싱을 활성화하지 않는 이유는 무엇입니까?

주로 사용 시나리오로 인해 :

① 캐시의 데이터 저장 형식에 대해 말씀 드리겠습니다. 키 (sql 문)-값 (데이터 값)이므로 SQL 문 (키)에 약간의 차이가 있으면 데이터베이스를 직접 쿼리합니다.

② 테이블의 데이터는 정적이 아니므로 대부분 자주 변경되며 데이터베이스의 데이터가 변경되면이 테이블과 관련된 해당 캐시 데이터를 제거해야합니다.

3. 분석 / 파서 :

분석기의 작업은 주로 실행할 SQL 문을 구문 분석하고 마지막으로 추상 구문 트리를 가져온 다음 전처리기를 사용하여 추상 구문 트리의 테이블이 있는지 여부를 확인한 다음 선택 항목이 있는지 확인하는 것입니다. 프로젝션 열 필드는 테이블에 존재합니다.

(1) 어휘 분석 :

어휘 분석은 SQL을 토큰이라고하는 분할 할 수없는 원자 기호로 분해하는 데 사용됩니다. 그리고 서로 다른 데이터베이스 방언에서 제공하는 사전에 따라 키워드, 표현, 리터럴 및 연산자로 분류됩니다.

(2) 구문 분석 :

구문 분석은 어휘 분석을 통해 분해 된 Token (원자 기호)을 기반으로 SQL 문을 추상 구문 트리로 변환하는 것입니다.

다음은 SQL 추상 구문 책이 어떻게 생겼는지 보여주는 직접적인 예입니다.

SELECT id, name FROM t_user WHERE status = 'ACTIVE' AND age > 18

위 SQL 문의 어휘 분석과 문법 분석을 거쳐 얻은 추상 문법 집은 다음과 같다.

이해하기 쉽도록 추상 구문 트리에서 키워드의 토큰은 녹색으로, 변수의 토큰은 빨간색으로, 회색은 추가 분할이 필요함을 나타냅니다.

(3) 전 처리기 :

생성 된 추상 구문 트리 에서  의미 론적 검증 수행 하기 위해 전처리가 사용되며,  의미 론적 검증은 쿼리 테이블을 검증하고 프로젝션 컬럼 필드를 선택하여 테이블과 필드가 존재하는지 여부를 결정하는 것입니다.

4. 최적화 :

Optimizer의 기능은 주로 SQL의 어휘 분석 / 구문 분석 후 얻은 문법 트리를 MySQL 데이터 사전의 내용과 통계 정보를 통한 일련의 계산을 통해  가져와 최종적으로 선택 사항을 포함한 실행 계획을 얻는 것입니다. 사용할 색인.

최적화 프로세스에서 일련의 계산은 무엇입니까?

(1) 논리 변환 : 예를 들어 SQL에 8> 9 조건이 있습니다. 논리 변환은 구문 트리의 상수 표현식을 false로 직접 단순화하는 것입니다. 단순화 외에도 상수 표현식도 있습니다. 기타

(2) 비용 최적화 : 데이터의 통계 분석 비용을 지불하여 SQL 실행을 인덱싱 할 수 있는지 여부 및 이동할 인덱스를 얻습니다. 또한 다중 테이블 관련 쿼리에서 최종 테이블의 순서를 결정합니다. 가입 등. ;

인덱스 질의 사용 여부를 분석 할 때 동적 데이터 샘플링 및 통계 분석 을 수행하여 얻어지며 , 통계적으로 분석하는 한 분석 오류가 발생할 수 있으므로 SQL 실행시 인덱스를 사용하지 않을 때 이러한 측면을 고려해야합니다. . 요소

MySql 실행 계획을 확인하는 방법은 무엇입니까? 실행 된 SQL 문 앞에 Explain 키워드를 추가하기 만하면됩니다.

5. 액추에이터 :

MySQL은 분석기를 통해 수행 할 작업을 알고 옵티 마이저를 통해 수행 할 작업을 알고 있으므로 executor 단계로 들어가 명령문 실행을 시작합니다. 실행기는 마지막으로 스토리지 엔진에서 제공하는 API 인터페이스를 호출하여 일련의 실행 계획에 따라 운영 데이터를 호출하여 SQL 실행을 완료합니다.

실행을 시작할 때 먼저 연결된 객체에이 테이블에 대한 작업을 수행 할 수있는 권한이 있는지 확인해야합니다. 그렇지 않은 경우 권한 없음 오류를 반환하고, 권한이있는 경우 생성 된 실행 계획에 따라 실행합니다.

 

세, InnoDB 스토리지 엔진 :

스토리지 엔진은 기본 물리적 데이터에 대한 실제 작업을 수행하는 구성 요소이며 서버 계층의 데이터를 운영하기위한 다양한 API를 제공하며 데이터는 메모리 또는 디스크에 저장됩니다. MySQL은 InnoDB, MyISAM, 메모리 등을 포함한 플러그인 스토리지 엔진을 지원합니다. 일반적으로 MySQL에서 사용하는 스토리지 엔진은 기본적으로 InnoDB입니다. 아래 그림과 같이 InnoDB 스토리지 엔진은 전체적으로 메모리 구조 (Memory Structures)와 디스크 구조 (Disk Structures)로 나뉩니다.

1, 버퍼 풀 :

Buffer Pool (버퍼 풀)은 InnoDB 스토리지 엔진에서 매우 중요한 메모리 구조로 Redis처럼 작동하며 캐시 역할을합니다. MySQL 데이터는 궁극적으로 디스크에 저장되며 Buffer Pool이 없으면 모든 데이터베이스 요청이 디스크에서 검색되므로 필연적으로 IO 작업이 발생합니다. 그러나 버퍼 풀을 사용하면 첫 번째 쿼리 만 쿼리 결과를 버퍼 풀에 저장하므로 후속 요청이있을 때 버퍼 풀에서 먼저 쿼리합니다. 디스크에서 찾을 수없는 경우 그런 다음 아래와 같이 버퍼 풀에 넣습니다.

이미지 -20210105101150038

UPDATE students SET stuName = '小强' WHERE id = 1

예를 들어이 SQL의 경우 위 그림에 따르면 SQL 문의 실행 단계는 대략 다음과 같습니다.

  • (1) innodb 스토리지 엔진은 먼저 버퍼 풀에서 id = 1 인 데이터가 있는지 검색합니다.
  • (2) 캐시가없는 경우 디스크에로드하여 버퍼 풀에 저장
  • (3) 독점 잠금이 레코드에 추가됩니다.

비고 :

버퍼 풀과 쿼리 캐시의 차이점 :

(1) 쿼리 캐시 : 쿼리 캐시는 서버 계층에 위치하며 MySQL 서버는 먼저 쿼리 캐시에서 SQL이 실행되었는지 확인합니다. 실행이 완료되면 이전에 실행 된 쿼리 결과가 쿼리 캐시에 저장됩니다. 키-값 형식으로. 키는 SQL 문이고 값은 쿼리 결과입니다. 이 프로세스 쿼리 캐싱이라고합니다!

(2) 버퍼 풀은 스토리지 엔진 계층에 있습니다. 버퍼 풀은 데이터 읽기 속도를 높이기 위해 MySQL 스토리지 엔진에 의해 설계된 버퍼링 메커니즘입니다.

2. 로그 파일 실행 취소 : 데이터가 수정되기 전에 어떤 모습인지 기록합니다.

Innodb 스토리지 엔진의 가장 큰 특징은 트랜잭션을 지원하는 것입니다. 트랜잭션이 커밋되지 않으면 트랜잭션의 모든 작업을 실행 전 상태로 롤백해야하며이 롤백 작업은 실행 취소 로그 파일을 사용하여 수행됩니다.

이름에서 알 수 있듯이 실행 취소는 아무 일도 일어나지 않았 음을 의미합니다. 실행 취소 로그는 아무 일도 일어나지 않은 일부 로그입니다 (원래 내용).

우리는 방금 SQL 문 업데이트를 준비 할 때 해당 문에 해당하는 데이터를 Buffer pool에로드했다고 소개했습니다. 실제로 여기에는 문을 Buffer Pool에로드하는 작업이 있습니다. 동시에 로그가 실행 취소 로그 파일에 삽입됩니다. 즉, id = 1 인 레코드의 원래 값이 기록되므로 트랜잭션 실패 후 롤백 할 수 있습니다.

이때 실행 한 SQL 문에 해당하는 데이터가 Buffer Pool에로드 된 후이 문을 업데이트하기 시작하며 실제로 Buffer Pool에서 업데이트 작업이 수행됩니다. 문제는 데이터를 업데이트 한 후 버퍼 풀의 데이터가 데이터베이스의 데이터베이스와 일치하지 않는다는 것입니다. 즉, 버퍼 풀의 데이터가 더티 데이터가되는 것입니까? 맞습니다, 현재 데이터는 더티 데이터입니다. 버퍼 풀의 레코드는 "Xiaoqiang"이고 데이터베이스의 레코드는 "Wangcai"입니다. MySQL은이 상황을 어떻게 처리합니까? 아래를 보자

3. 리두 로그 파일 : 수정 된 데이터의 모양을 기록합니다.

서문 : 리두 로그 파일은 InnoDB에 고유하며 MySQL 수준이 아닌 스토리지 엔진 수준에 있습니다.

디스크에서 파일을로드하고 작업 전 기록을 실행 취소 로그 파일에 저장하는 것 외에도 메모리에서 다른 작업이 완료됩니다. 메모리에있는 데이터의 특성은 다음과 같습니다. 이때 MySQL이 다운 된 서버는 Buffer Pool의 모든 데이터가 손실됩니다. 이때 리두 로그 파일은 그 마법을 보여줄 필요가 있습니다.

다시 실행은 할 준비가되어 있고 할 준비가되었음을 의미합니다. 다시 실행 로그는 수행 될 몇 가지 작업을 기록합니다. 예를 들어, 이때 수행 할 작업은 학생 set stuName = 'Xiaoqiang'where id = 1을 업데이트하는 것입니다. 그러면이 작업은 리두 로그 버퍼에 기록됩니다. 리두 로그 버퍼는 효율성 향상을 위해 MySQL이므로 이 작업은 먼저 메모리에 넣어 완료

이때 서버가 다운되었다고 가정하면 캐시의 데이터는 여전히 손실됩니다. 메모리 대신 디스크에 직접 저장할 수 있습니까? 메모리에서 작업의 목적이 효율성을 향상시키는 것이라고 위에서 소개 되었기 때문에 분명히 아닙니다. 이 시점에서 MySQL이 실제로 다운 되어도 문제가되지 않습니다. MySQL은이 트랜잭션을 실패로 간주하므로 데이터는 업데이트 전과 동일하며 영향을 미치지 않습니다.

이 시점에서 SQL 문도 갱신 된 다음 갱신 된 값을 제출해야합니다. 즉, 트랜잭션을 제출해야합니다. 트랜잭션이 성공적으로 제출되면 마지막 변경 사항이 데이터베이스에 저장됩니다. 리두 로그 버퍼의 데이터를 디스크에 유지하는 것은 리두 로그 버퍼의 데이터를 리두 로그 디스크 파일에 쓰는 것입니다.

리두 로그 버퍼가 디스크로 플러시 된 후 데이터베이스 서버가 다운되면 업데이트 된 데이터로 어떻게해야합니까? 이때 데이터는 메모리에 있습니다. 데이터가 손실되지 않습니까? 아니요, 리두 로그 버퍼의 데이터가 디스크에 기록되고 유지 되었기 때문에 이번에는 데이터가 손실되지 않습니다. 데이터베이스가 다운 되더라도 MySQL은 다음에 다시 시작할 때 로그 파일을 다시 실행합니다. 컨텐츠가 버퍼 풀로 복원됩니다.

  • (1) SQL 문 업데이트 준비
  • (2) MySQL (innodb)은 먼저 버퍼 풀 (Buffer Pool)로 이동하여 데이터를 찾습니다. 찾지 못한 경우 디스크로 이동하여 찾은 경우 버퍼에 데이터를로드합니다. pool (버퍼 풀)
  • (3) 버퍼 풀에로드하는 동안이 데이터의 원본 레코드는 실행 취소 로그 파일에 저장됩니다.
  • (4) Innodb는 Buffer Pool에서 업데이트 작업을 수행합니다.
  • (5) 업데이트 된 데이터는 리두 로그 버퍼에 기록됩니다.
  • (6) MySQL이 트랜잭션을 커밋 할 때 리두 로그 버퍼의 데이터를 리두 로그 파일에 기록합니다. 디스크 비우기는 innodb_flush_log_at_trx_commit 매개 변수로 설정할 수 있으며, 값 0은 디스크로 비우기가 없음을 의미합니다. 값 1은 즉시 디스크를 비우는 것을 의미하고, 값 2는 OS 캐시로 먼저 플래싱을 의미합니다. 정상적인 상황에서 즉시 디스크로 플래시
  • (7) myslq가 다시 시작되면 리두 로그가 버퍼 풀로 복원됩니다.

4. 빈 로그 로그 파일 : 전체 작업 프로세스를 기록

서문 : 빈 로그와 리두 로그는 다소 유사하며 두 가지의 주요 차이점은 다음과 같습니다.

(1) Redo 로그는 InnoDB 스토리지 엔진에 고유 한 로그 파일이며 bin 로그는 MySQL 수준의 로그입니다.

(2) Redo 로그는 크래시 복구에 적합하며 bin 로그는 마스터-슬레이브 복제 및 데이터 복구에 적합합니다.

리두 로그에 기록 된 것은 "어떤 데이터와 어떤 변경이 이루어 졌는지"와 같은 물리적 속성에 편향되어 있습니다. bin 로그는 "업데이트 작업이 학생 테이블에서 ID가 1 인 레코드에 임대됩니다"와 같이 논리적 특성에 편향되어 있습니다.

bin 로그 파일은 어떻게 디스크에  플러시 됩니까? bin 로그 플러시 전략은 sync_bin 로그를 통해 수정할 수 있습니다. 기본값은 0이며, 이는 먼저 OS 캐시에 기록됨을 의미합니다. 커밋되면 데이터가 디스크로 직접 전송되지 않습니다., 따라서 bin 로그 데이터가 다운 되어도 데이터는 여전히 손실됩니다. 따라서 sync_bin log를 1로 설정하는 것이 좋습니다. 즉, 디스크 파일에 직접 데이터를 쓰는 것을 의미합니다.

bin 로그도 로그 파일이므로 어디에 데이터를 기록합니까? 실제로 MySQL이 트랜잭션을 커밋하면 리두 로그 버퍼의 데이터를 리두 로그 파일에 기록 할뿐만 아니라 수정 된 데이터를 bin 로그 파일에 기록하고 이번에는 수정 된 bin도 기록합니다. 로그 파일 이름의 위치와 bin 로그의 수정 된 내용이 리두 로그에 기록되고 마지막으로 커밋 표시가 리두 로그 끝에 기록되어 트랜잭션이 성공적으로 커밋되었음을 의미합니다.

데이터가 bin 로그 파일에 기록 될 때 기록이 완료된 직후 데이터베이스가 다운되면 데이터가 손실됩니까?

가장 먼저 확인해야 할 것은 리두 로그 끝에 커밋 표시가없는 한이 트랜잭션이 실패했음을 의미합니다. 그러나 데이터는 리두 로그의 디스크 파일에 기록 되었기 때문에 손실되지 않습니다. MySQL이 다시 시작되면 리두 로그의 데이터가 버퍼 풀로 복원 (로드)됩니다.

글쎄, 지금까지 기본적으로 업데이트 작업을 도입했지만 아직 완료되지 않은 것이 있다고 생각하십니까? 또한 현재 업데이트 된 레코드는 시스템이 다운되고 재개 된 경우에도 메모리에서만 실행된다는 사실을 발견 했습니까? 업데이트 된 레코드를 버퍼 풀로로드하는 것뿐입니다. 이때 MySQL 데이터베이스의 레코드는 여전히 남아 있습니다. 즉, 메모리의 데이터는 여전히 더티 데이터라고 생각하는 이전 값입니다.이 시점에서 무엇을해야합니까?

실제로 MySQL에는 백그라운드 스레드가있어 버퍼 풀의 더티 데이터를 특정 시간에 MySQL 데이터베이스로 플러시하여 메모리와 데이터베이스 데이터가 통합됩니다.

5. 요약 :

  • (1) 먼저 MySQL 실행기는 스토리지 엔진 API를 호출하여 실행 계획에 따라 데이터를 쿼리합니다.
  • (2) 스토리지 엔진은 먼저 버퍼 풀의 버퍼 풀에서 데이터를 쿼리하고 그렇지 않은 경우 쿼리를 위해 디스크로 이동하고 쿼리하면 버퍼 풀에 배치됩니다.
  • (3) 데이터가 버퍼 풀에로드되면이 데이터의 원본 레코드가 실행 취소 로그 파일에 저장됩니다.
  • (4) Innodb는 Buffer Pool에서 업데이트 작업을 수행합니다.
  • (5) 업데이트 된 데이터는 리두 로그 버퍼에 기록됩니다.
  • (6) 커밋 트랜잭션은 커밋하는 동안 다음 세 가지를 수행합니다.
  • (7) (먼저) 리두 로그 버퍼의 데이터를 리두 로그 파일로 플러시합니다.
  • (8) (두 번째)이 작업 기록을 bin 로그 파일에 씁니다.
  • (9) (세 번째) bin 로그 파일의 이름과 업데이트 된 내용의 위치를 ​​다시 실행 로그의 bin 로그에 기록하고 다시 실행 로그 끝에 커밋 표시를 추가합니다.
  • (10) 백그라운드 스레드를 사용하여 버퍼 풀의 업데이트 된 데이터를 특정 시간에 MySQL 데이터베이스로 플러시하여 메모리와 데이터베이스 데이터를 통합합니다.

 

참조 기사 :

https://juejin.cn/post/6897388295060684807

https://juejin.cn/post/6920076107609800711

추천

출처blog.csdn.net/a745233700/article/details/113927318