기술나눔

MySQL 실기 45개 강의 스터디 노트 (지속적으로 업데이트...)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina


1. 인프라: SQL 쿼리문은 어떻게 실행되나요?

개요

여기에 이미지 설명을 삽입하세요.

일반적으로 MySQL은 두 개의 계층으로 나눌 수 있습니다.

  • 서버 계층
    MySQL의 핵심 서비스 기능 대부분을 다룹니다.
    • 커넥터
    • 쿼리 캐시
    • 분석기
    • 옵티마이저
    • 액추에이터
    • 모든 내장 기능(예: 날짜, 시간, 수학 및 암호화 기능 등)
    • 스토리지 엔진 전반의 기능
      • 저장 프로시저
      • 방아쇠
      • 보다
      • ……
  • 스토리지 엔진 레이어
    데이터 저장 및 검색을 담당하는 플러그인 아키텍처
    • 이노디비
    • 마이ISAM
    • 메모리

커넥터

mysql -h$ip -P$port -u$user -p
  • 1

연결 명령의 mysql은 서버와의 연결을 설정하는 데 사용되는 클라이언트 도구입니다.클래식 TCP 핸드셰이크를 완료한 후 커넥터는
이때 입력하신 사용자 이름과 비밀번호가 사용됩니다.

  • 사용자 이름이나 비밀번호가 올바르지 않은 경우 "사용자에 대한 접근이 거부되었습니다" 오류가 발생하고 클라이언트 프로그램이
    실행을 종료합니다.
  • 사용자 이름과 비밀번호 인증이 통과되면 커넥터는권한 테이블 거기에서 어떤 권한을 갖고 있는지 알아보세요.이후에는 이와 관련해
    권한 판단 논리는 이때 읽은 권한에 따라 달라집니다.

여기에 이미지 설명을 삽입하세요.
클라이언트가 너무 오랫동안 비활성 상태이면 커넥터가 자동으로 연결을 끊습니다. 이 시간은 wait_timeout 매개변수로 제어되며 기본값은 8시간입니다.

연결이 끊어진 후 클라이언트가 다시 요청을 보내면 오류 알림을 받게 됩니다. Lost connection to MySQL server during query . 지금 계속 진행하려면 다시 연결한 후 요청을 실행해야 합니다.

데이터베이스에서 연결이 길다는 것은 연결이 성공한 후에도 클라이언트가 계속해서 요청을 하면 항상 동일한 연결이 사용된다는 의미입니다. 짧은 연결은 몇 번의 쿼리가 실행된 후 연결이 끊어지고 다음 쿼리를 위해 새 연결이 다시 설정되는 것을 의미합니다.

일반적으로 연결을 설정하는 과정은 복잡하므로 사용 중에 연결을 설정하는 작업을 최소화하는 것, 즉 긴 연결을 사용하는 것이 좋습니다.

그러나 긴 연결을 모두 사용한 후에 MySQL이 차지하는 메모리가 매우 빠르게 증가하는 경우가 있습니다.MySQL이 실행 중 일시적으로 사용하는 메모리는 연결 개체에서 관리됩니다. . 이러한 리소스는 연결이 끊어지면 해제됩니다.그래서 만약긴 연결이 누적되면 과도한 메모리 사용량이 발생할 수 있습니다., 시스템(OOM)에 의해 강제 종료된 현상으로 보아 MySQL이 비정상적으로 재시작되었습니다.

이 문제를 해결하는 방법? 다음 두 가지 옵션을 고려할 수 있습니다.

  • 긴 연결을 주기적으로 끊습니다. . 일정 기간 사용 후 또는 프로그램에서 메모리를 차지하는 큰 쿼리가 실행된 것으로 판단한 후 연결이 끊어진 후 쿼리가 필요했다가 다시 연결됩니다.
  • MySQL 5.7 이상을 사용하는 경우 다음을 실행할 수 있습니다. mysql_reset_connection 연결 리소스를 다시 초기화합니다. 이 프로세스에는 재연결 및 권한 확인이 필요하지 않지만 방금 생성된 상태로 연결을 복원합니다.

쿼리 캐시

MySQL은 쿼리 요청을 받은 후 먼저 쿼리 캐시로 이동하여 이전에 이 명령문이 실행되었는지 확인합니다. 이전에 실행된 명령문과 그 결과는 키-값 쌍의 형태로 메모리에 직접 캐시될 수 있습니다. 키는 쿼리문이고, 값은 쿼리 결과입니다. 쿼리가 이 캐시에서 직접 키를 찾을 수 있으면 값이 클라이언트에 직접 반환됩니다.

문이 쿼리 캐시에 없으면 실행 단계가 계속됩니다. 실행이 완료된 후 실행 결과는 쿼리 캐시에 저장됩니다. 쿼리가 캐시에 도달하면 MySQL은 후속 복잡한 작업을 수행하지 않고 결과를 직접 반환할 수 있으므로 매우 효율적이라는 것을 알 수 있습니다.

하지만 대부분의 경우 나는 그럴 것이다.쿼리 캐싱을 사용하지 않는 것이 좋습니다. ,왜? 쿼리 캐싱은 종종 득보다 실이 더 많기 때문입니다.

쿼리 캐시는 매우 자주 무효화됩니다. 테이블이 업데이트되는 한 이 테이블의 모든 쿼리 캐시는 지워집니다. 따라서 결과를 저장하는 데 어려움을 겪었고 사용하기도 전에 업데이트로 인해 결과가 지워졌을 가능성이 있습니다. 업데이트 압력이 심한 데이터베이스의 경우 쿼리 캐시 적중률이 매우 낮습니다. 귀하의 비즈니스에 오랫동안 한 번만 업데이트되는 정적 테이블이 있지 않는 한. 예를 들어 시스템 구성 테이블인 경우 이 테이블의 쿼리는 쿼리 캐시에 적합합니다.

다행스럽게도 MySQL은 이러한 "요청 시 사용" 방법도 제공합니다. 기본 SQL 문에 쿼리 캐시가 사용되지 않도록 query_cache_type 매개 변수를 DEMAND로 설정할 수 있습니다. 쿼리 캐시를 사용하려는 명령문의 경우 다음 명령문과 같이 SQL_CACHE를 사용하여 명시적으로 지정할 수 있습니다.

select SQL_CACHE * from T where ID=10;
  • 1

인지해야 한다는 것은,MySQL 8.0 버전에서는 전체 쿼리 캐시 기능을 직접 삭제합니다., 이는 이 기능이 8.0부터 더 이상 사용할 수 없음을 의미합니다.

분석기

쿼리 캐시가 적중되지 않으면 문의 실제 실행이 시작됩니다. 먼저 MySQL은 사용자가 수행하려는 작업이 무엇인지 알아야 하므로 SQL 문을 구문 분석해야 합니다.

여기에 이미지 설명을 삽입하세요.

옵티마이저

여기에 이미지 설명을 삽입하세요.
여기에 이미지 설명을 삽입하세요.

액추에이터

여기에 이미지 설명을 삽입하세요.
여기에 이미지 설명을 삽입하세요.

2. 로깅 시스템: SQL 업데이트 문은 어떻게 실행되나요?

여기에 이미지 설명을 삽입하세요.

다시 실행 로그

"공이지"라는 기사를 아직도 기억하실지 모르겠습니다. 호텔 매니저는 손님의 신용 기록을 기록하는 데 특별히 사용되는 분홍색 보드를 가지고 있습니다. 신용카드로 결제하는 사람이 많지 않으면 게시판에 고객의 이름과 계좌를 적을 수 있습니다. 그러나 신용 계좌를 가진 사람이 너무 많으면 팬 보드가 그들을 추적할 수 없는 경우가 항상 있습니다. 이 때 상점 주인은 신용 계좌를 기록하기 위한 특별한 장부를 가지고 있어야 합니다.

누군가가 빚을 갚거나 빚을 갚고자 할 경우, 가게 주인은 일반적으로 두 가지 선택권이 있습니다.

  • 한 가지 방법은 원장을 직접 열고 신용 계좌를 추가하거나 빼는 것입니다.
  • 또 다른 접근법은이번에는 핑크색 판에 먼저 장부를 적고, 마감 시간이 지나면 장부를 꺼내서 계산해 보세요.

장사가 번창하고 카운터가 바쁠 때 가게 주인은 반드시 선택할 것입니다후자의 , 이전 작업이 너무 번거롭기 때문입니다. 먼저, 이 사람의 총 신용 계좌 기록을 찾아야 합니다. 생각해 보세요. 이름을 찾으려면 가게 주인이 돋보기를 쓰고 천천히 검색해야 할 수도 있습니다. 계산을 위해 주판을 꺼내고 마침내 결과를 다시 입력합니다. 원장.

이 모든 과정은 생각하기가 번거롭습니다. 대조적으로, 분홍색 판에 먼저 적어 두는 것이 더 쉽습니다. 생각해 보세요, 가게 주인이 핑크보드의 도움을 받지 못하면 장부를 기록할 때마다 장부를 뒤집어야 하기 때문에 효율성이 참을 수 없을 정도로 낮지 않습니까?

마찬가지로 이 문제는 MySQL에도 존재합니다. 모든 업데이트 작업을 디스크에 기록해야 하고 디스크도 업데이트 전에 해당 레코드를 찾아야 한다면 전체 프로세스의 IO 비용과 검색 비용이 매우 높을 것입니다. 이 문제를 해결하기 위해 MySQL의 디자이너들은 호텔 점원의 핑크보드와 유사한 아이디어를 활용하여 업데이트 효율성을 향상시켰습니다.

핑크보드와 원장 사이의 전체 협력 과정은 실제로 MySQL에서 자주 언급되는 내용이다. WAL 기술,WAL 전체 이름은Write-Ahead Logging, 핵심은로그를 먼저 쓴 다음 디스크에 씁니다.즉, 핑크색 판을 먼저 쓰고, 바쁘지 않을 때 장부를 쓰세요.

구체적으로, 레코드를 업데이트해야 할 경우 InnoDB 엔진은 먼저 해당 레코드를 리두 로그(핑크보드)에 기록하고 메모리를 업데이트합니다. 이때 업데이트가 완료됩니다. 동시에 InnoDB 엔진은 적절한 시간에 디스크에 작업 기록을 업데이트하며, 이 업데이트는 가게 주인이 문을 닫은 후 하는 것처럼 시스템이 상대적으로 유휴 상태일 때 수행되는 경우가 많습니다.

오늘 신용 계좌가 많지 않으면 상점 주인은 품목을 분류하기 위해 마감 시간까지 기다릴 수 있습니다. 그런데 특정일에 신용계좌가 많아 핑크보드가 가득 차면 어떻게 해야 할까요? 이때 가게 주인은 자신의 일을 내려놓고 핑크보드에 있는 신용기록 중 일부를 원장에 업데이트한 뒤 핑크보드에서 이 기록을 지워 새로운 계좌를 위한 공간을 마련해야 했다.

마찬가지로 InnoDB의 redo 로그는 고정된 크기를 가지고 있습니다. 예를 들어 4개의 파일 세트로 구성할 수 있으며 각 파일의 크기는 1GB입니다. 그러면 이 "핑크 보드"는 총 4GB 작업을 기록할 수 있습니다. 처음부터 쓰기를 시작한 다음, 아래 그림과 같이 처음으로 돌아가서 루프를 작성합니다.

여기에 이미지 설명을 삽입하세요.
write pos는 현재 레코드의 위치입니다. 쓰기 중 뒤로 이동합니다. 3번 파일의 끝 부분에 쓴 후 0번 파일의 처음으로 돌아갑니다. 체크포인트는 삭제될 현재 위치이며, 레코드를 삭제하기 전에 레코드를 데이터 파일로 업데이트해야 합니다.

쓰기 위치와 체크포인트 사이의 공간은 새로운 작업을 기록하는 데 사용할 수 있는 "핑크 보드"의 빈 부분입니다. 쓰기 위치가 체크포인트를 따라잡는다면 '핑크보드'가 꽉 찼다는 의미이며, 현재로서는 새로운 업데이트를 수행할 수 없다는 뜻입니다. 체크포인트를 진행하려면 먼저 일부 기록을 중지하고 삭제해야 합니다.

InnoDB는 Redo 로그를 통해 데이터베이스가 비정상적으로 재시작되더라도 이전에 제출된 레코드가 손실되지 않도록 보장할 수 있습니다.crash-safe

충돌 방지 개념을 이해하려면 이전 신용 기록 예시를 생각해 보세요. 핑크보드나 장부에 신용기록이 기록되어 있기만 하면 점주가 갑자기 며칠간 영업을 중단하는 등 나중에 잊어버리더라도 장부의 데이터를 통해 신용계좌를 명확히 할 수 있고, 영업 재개 후 핑크보드.

바이너리로그

이전에 말했듯이 MySQL은 실제로 두 부분으로 구성됩니다. 하나는 주로 MySQL의 기능 수준에서 작업을 수행하는 서버 계층이고, 다른 하나는 스토리지와 관련된 특정 문제를 담당하는 엔진 계층입니다.위에서 이야기한 핑크보드리두 로그는 InnoDB 엔진 고유의 로그입니다.,그리고 서버 계층에는 binlog(아카이브 로그)라는 자체 로그도 있습니다.

내 생각에 당신은 왜 두 개의 로그가 있습니까?

MySQL에는 처음에는 InnoDB 엔진이 없었기 때문입니다. MySQL의 자체 엔진은 MyISAM이지만 MyISAM에는 충돌 방지 기능이 없으며 binlog 로그는 보관에만 사용할 수 있습니다. InnoDB는 다른 회사에서 플러그인 형태로 MySQL에 도입했습니다. binlog에만 의존하면 충돌 방지 기능이 없으므로 InnoDB는 충돌 방지 기능을 달성하기 위해 다른 로그 시스템, 즉 redo 로그를 사용합니다.

이 두 로그에는 다음과 같은 세 가지 차이점이 있습니다.

  1. redo 로그는 InnoDB 엔진에 고유합니다. binlog는 MySQL의 서버 계층에서 구현되며 모든 엔진에서 사용할 수 있습니다.
  2. 리두 로그는 물리적 로그입니다., "특정 데이터 페이지에서 수정된 내용"을 기록합니다.binlog는 논리적 로그입니다., 기록된 내용은 "ID=2인 행의 c 필드에 1을 추가합니다"와 같은 이 문의 원래 논리입니다.
  3. 리두 로그는 루프로 기록됩니다., 공간이 모두 소모됩니다.binlog를 추가로 작성할 수 있습니다. . "쓰기 추가"는 binlog 파일이 특정 크기에 도달한 후 다음 파일로 전환하고 이전 로그를 덮어쓰지 않음을 의미합니다.

이 두 로그에 대한 개념적 이해를 바탕으로, 이 간단한 업데이트 문을 실행할 때 실행기와 InnoDB 엔진의 내부 프로세스를 살펴보겠습니다.

  1. 실행자는 먼저 라인 ID=2를 얻기 위해 엔진을 찾습니다. ID는 기본 키이며 엔진은 이 행을 찾기 위해 트리 검색을 직접 사용합니다. ID=2인 행이 있는 데이터 페이지가 이미 메모리에 있으면 실행기로 직접 반환됩니다. 그렇지 않으면 먼저 디스크에서 메모리로 읽어온 다음 반환해야 합니다.
  2. 실행기는 엔진에서 제공한 행 데이터를 가져오고 이 값에 1을 더합니다. 예를 들어 이전에는 N이었지만 지금은 N+1이며 새 데이터 행을 가져온 다음 엔진 인터페이스를 호출하여 다음을 작성합니다. 새로운 데이터 행.
  3. 엔진은 이 새로운 데이터 행을 메모리에 업데이트하고 이때 리두 로그에 업데이트 작업을 기록합니다. 다시 실행 로그 ~에준비하다 상태. 그런 다음 실행이 완료되었으며 언제든지 트랜잭션을 제출할 수 있음을 실행자에게 알립니다.
  4. 실행자는 이 작업의 binlog를 생성하고 디스크에 기록된 binlog
  5. 실행자는 엔진의 커밋 트랜잭션 인터페이스를 호출하고 엔진은 다시 실행 로그 제출로 변경(저지르다) 상태이면 업데이트가 완료되었습니다.

여기에 이 ​​업데이트 문의 실행 흐름도가 나와 있습니다. 그림의 밝은 상자는 InnoDB 내에서 실행됨을 나타내고 어두운 상자는 실행기에서 실행됨을 나타냅니다.

여기에 이미지 설명을 삽입하세요.
업데이트 문 실행 프로세스

마지막 세 단계는 약간 "순환"처럼 보입니다. 리두 로그 작성은 준비와 커밋의 두 단계로 나누어집니다.

2단계 커밋

왜 "2단계 제출"이 필요한가요?이는 두 로그 간의 차이를 허용하기 위한 것입니다.논리적으로 일관성 . 이 문제를 설명하려면 기사 시작 부분에 있는 질문부터 시작해야 합니다. 반달 내에 데이터베이스를 임의의 초 상태로 복원하는 방법은 무엇입니까?

이전에 말했듯이 binlog는 모든 논리 연산을 기록하고 "쓰기 추가" 형식을 채택합니다. DBA가 반달 이내에 복원할 수 있다고 약속하면 백업 시스템은 확실히 지난 반달의 모든 binlog를 저장하고 시스템은 전체 데이터베이스에 대한 정기적인 백업을 수행합니다. 여기서 "정규"는 시스템의 중요성에 따라 달라지며 하루에 한 번 또는 일주일에 한 번일 수 있습니다.

예를 들어 어느 날 오후 2시에 지정된 초로 복원해야 하는 경우 정오에 실수로 테이블이 삭제된 것을 발견하고 데이터를 검색해야 하는 경우 다음과 같이 할 수 있습니다.

  • 먼저 가장 최근의 전체 백업을 찾으십시오. 운이 좋으면 어젯밤의 백업일 수 있으며 이 백업에서 임시 데이터베이스로 복원하십시오.
  • 이후 백업 시점부터 순차적으로 백업 binlog를 꺼내어 정오에 실수로 테이블이 삭제되기 전 시점까지 재생한다.
    이런 방식으로 임시 데이터베이스는 실수로 삭제하기 전의 온라인 데이터베이스와 동일하게 됩니다. 그러면 필요에 따라 임시 데이터베이스에서 테이블 데이터를 꺼내 온라인 데이터베이스에 복원할 수 있습니다.

자, 데이터 복구 프로세스에 대해 이야기한 후 다시 돌아와서 로그에 "2단계 커밋"이 필요한 이유에 대해 이야기해 보겠습니다. 여기서 우리는 설명하기 위해 모순에 의한 증명을 사용할 수도 있습니다.

Redo 로그와 binlog는 두 개의 독립적인 로직이므로 two-phase commit을 사용하지 않는 경우 redo 로그를 먼저 작성한 후 binlog를 작성하거나 역순을 채택해야 한다. 이 두 가지 방법에 어떤 문제가 있는지 살펴보겠습니다.

이전 업데이트 문을 예로 사용하세요. ID=2인 현재 행의 c 필드 값이 0이라고 가정하고 업데이트 문을 실행하는 동안 첫 번째 로그가 기록된 후 두 번째 로그가 기록되기 전에 충돌이 발생한다고 가정하면 어떻게 될까요?

  • 먼저 redo log를 작성한 다음 binlog를 작성하세요.
    redo 로그가 기록될 때 binlog가 기록되기 전에 MySQL 프로세스가 비정상적으로 다시 시작된다고 가정해 보겠습니다. 앞서 말했듯이 리두 로그가 작성된 후 시스템이 충돌하더라도 데이터는 여전히 복원될 수 있으므로 복구 후 이 줄의 c 값은 1입니다. 그러나 binlog가 완료되기 전에 충돌이 발생했기 때문에 이 명령문은 현재 binlog에 기록되지 않았습니다. 따라서 나중에 로그를 백업할 때 저장된 binlog에 이 문장은 포함되지 않습니다. 그러면 이 binlog를 사용하여 임시 라이브러리를 복원해야 하는 경우 이 명령문의 binlog가 손실되므로 이번에는 임시 라이브러리가 업데이트되지 않습니다. 복원된 행의 c 값은 0입니다. 원래 라이브러리의 값과 동일합니다.
  • 먼저 binlog를 작성한 다음 로그를 다시 실행하세요.
    binlog가 작성된 후 충돌이 발생하면 redo 로그가 아직 작성되지 않았으므로 충돌 복구 후 트랜잭션이 유효하지 않으므로 이 줄의 c 값은 0입니다. 그러나 "Change c from 0 to 1" 로그가 binlog에 기록되었습니다. 따라서 나중에 binlog를 사용하여 복원하면 트랜잭션이 하나 더 나오게 되는데, 복원된 행의 c 값은 1로 원래 데이터베이스의 값과 다릅니다.
    "2단계 커밋"을 사용하지 않으면 데이터베이스의 상태가 해당 로그를 사용하여 복원된 라이브러리의 상태와 일치하지 않을 수 있음을 알 수 있습니다.

이 확률이 매우 낮습니까? 임시 라이브러리를 언제든지 복원해야 하는 상황은 없습니다.

실제로 아니요. 이 프로세스는 오작동 후 데이터를 복구하는 데만 필요한 것은 아닙니다. 용량을 확장해야 할 때, 즉 시스템의 읽기 용량을 늘리기 위해 더 많은 백업 데이터베이스를 구축해야 할 때, 이제 일반적인 관행은 전체 백업을 사용하고 이를 달성하기 위해 binlog를 적용하는 것입니다. 온라인 마스터 데이터베이스와 슬레이브 데이터베이스 간의 불일치입니다.

간단히 말해서, 리두 로그와 binlog는 모두 트랜잭션의 커밋 상태를 나타내는 데 사용될 수 있습니다.2단계 제출은 두 상태를 논리적으로 일관되게 유지하는 것입니다.