메뉴 여닫기
개인 메뉴 토글
로그인하지 않음
만약 지금 편집한다면 당신의 IP 주소가 공개될 수 있습니다.
MYSQL · FOUNDATION COURSE
MySQL 입문
웹 서비스에서 가장 많이 쓰이는 오픈소스 RDBMS — 설치와 접속부터 InnoDB 구조, 인덱스, 트랜잭션·락, 복제와 백업까지
처음 시작하는 사람과 Oracle 사용자를 위한 단계별 가이드
난이도 · 입문학습기간 · 10주기준 · MySQL 8.0 / 8.4 LTS비교 · Oracle 19c
STEP 1
개념 · 설치
MySQL의 특징, 설치와 mysql 클라이언트
STEP 2
SQL · 데이터 타입
DDL·DML, AUTO_INCREMENT, utf8mb4, JSON
STEP 3
InnoDB 구조
클러스터드 인덱스, 버퍼 풀, Redo·Undo·Binlog
STEP 4
성능 · 운영
인덱스·EXPLAIN, 락, 권한, 백업·복제

1. MySQL이란

MySQL은 1995년 스웨덴 MySQL AB가 공개한 오픈소스 관계형 데이터베이스로, 현재는 Oracle Corporation이 개발한다. 가볍고 빠르며 설치·운영이 쉬워 웹 서비스, 쇼핑몰, 게임, SaaS 등에서 가장 널리 쓰인다. 같은 뿌리에서 갈라진 MariaDB도 대부분 문법이 호환된다.

한 줄 정의
단순하고 빠른 읽기·쓰기에 강한, InnoDB 스토리지 엔진 기반의 대표적인 오픈소스 RDBMS

1.1 주요 특징

STORAGE ENGINE
플러그인 스토리지 엔진
SQL 계층과 저장 계층이 분리되어 있다. 기본이자 사실상 표준은 트랜잭션을 지원하는 InnoDB.
CLUSTERED
PK 순서로 저장
InnoDB 테이블은 기본키(PK) 순서로 정렬된 클러스터드 인덱스 구조다. PK 설계가 성능을 좌우한다.
REPLICATION
손쉬운 복제
Binlog 기반 소스-레플리카 복제, GTID, Group Replication / InnoDB Cluster로 확장과 고가용성을 구성한다.
EDITIONS
에디션
Community Edition(GPL, 무료)과 Enterprise Edition(상용, 백업·감사·방화벽 등 추가 기능).

1.2 Oracle과 한눈에 비교

구분 Oracle MySQL (InnoDB)
라이선스 상용 Community(GPL) / Enterprise(상용)
프로세스 구조 백그라운드 프로세스 + 서버 프로세스 단일 프로세스(mysqld) + 접속마다 스레드
테이블 저장 구조 힙 테이블 (기본), IOT 선택 PK 기준 클러스터드 인덱스 (Oracle IOT와 유사)
Undo / MVCC Undo 테이블스페이스 Undo 로그 기반 MVCC (Oracle과 비슷한 방식)
리두 로그 Redo Log / Archive Log InnoDB Redo Log + Binary Log(binlog) (복제·시점 복구용)
논리 구조 스키마 = 사용자 데이터베이스 = 스키마 (사용자와 별개, DB 간 조인 가능)
기본 격리 수준 READ COMMITTED REPEATABLE READ
트랜잭션 DDL 자동 커밋 자동 커밋 (DDL은 롤백 불가)
사용자 식별 사용자명 '사용자'@'호스트' 조합
실행계획 확인 DBMS_XPLAN EXPLAIN, EXPLAIN ANALYZE (8.0.18+)
고가용성 RAC, Data Guard 복제(Replication), InnoDB Cluster, MHA·Orchestrator 등

2. 설치와 접속

2.1 가장 빠른 방법 — Docker

docker run -d --name mysql-lab \
  -e MYSQL_ROOT_PASSWORD=lab1234 \
  -p 3306:3306 \
  -v mysqldata:/var/lib/mysql \
  mysql:8.4

docker exec -it mysql-lab mysql -uroot -p

2.2 Linux 패키지 설치 (Rocky/RHEL 계열 예)

# MySQL 공식 Yum 저장소 등록 후
sudo dnf install -y mysql-community-server
sudo systemctl enable --now mysqld
sudo grep 'temporary password' /var/log/mysqld.log   # 초기 root 임시 비밀번호
mysql_secure_installation                            # 비밀번호 변경·익명 계정 제거
Windows / macOS
MySQL Installer(Windows), DMG 패키지 또는 Homebrew(macOS)로 설치한다. GUI 도구로는 MySQL Workbench, DBeaver, HeidiSQL이 많이 쓰인다.

2.3 mysql 클라이언트 필수 명령

명령 의미 Oracle에서 비슷한 것
mysql -h 호스트 -P 3306 -u 사용자 -p 접속 sqlplus user@tns
SHOW DATABASES; 데이터베이스(스키마) 목록 DBA_USERS
USE dbname; 기본 DB 전환 ALTER SESSION SET CURRENT_SCHEMA
SHOW TABLES; 테이블 목록 USER_TABLES
DESC 테이블명; 컬럼 구조 DESC
SHOW CREATE TABLE 테이블명\G 테이블 DDL 전체 (인덱스·엔진 포함) DBMS_METADATA.GET_DDL
SHOW INDEX FROM 테이블명; 인덱스 목록 USER_INDEXES
SHOW PROCESSLIST; 접속 세션 목록 V$SESSION
SHOW VARIABLES LIKE 'innodb%'; 시스템 변수 SHOW PARAMETER
\G (문장 끝) 세로 출력 —
source file.sql 스크립트 실행 @file.sql

3. 논리 구조

 MySQL 서버 (mysqld 인스턴스 1개, datadir)
  ├─ 데이터베이스(=스키마) mysql               ← 사용자·권한 등 시스템 정보
  ├─ information_schema / performance_schema / sys ← 메타데이터·성능 정보
  ├─ 데이터베이스 shop
  │    ├─ 테이블 (InnoDB: 테이블마다 shop/orders.ibd 파일)
  │    ├─ 뷰, 트리거, 저장 프로시저/함수, 이벤트
  └─ 데이터베이스 board
  (공통) 사용자 'user'@'host' · 권한
중요
MySQL에서 DATABASE와 SCHEMA는 같은 말이다 (CREATE SCHEMA = CREATE DATABASE). 같은 서버 안이라면 shop.orders처럼 다른 데이터베이스의 테이블과 바로 조인할 수 있다.

4. 기본 SQL과 데이터 타입

4.1 주요 데이터 타입

용도 MySQL Oracle 대응 메모
정수 INT, BIGINT, TINYINT NUMBER(10) UNSIGNED 지정 가능
정밀 숫자 DECIMAL(p,s) NUMBER(p,s) 금액
문자 VARCHAR(n), TEXT VARCHAR2(n), CLOB n은 문자 수
날짜 DATE DATE MySQL DATE는 시간 없음
일시 DATETIME, TIMESTAMP DATE, TIMESTAMP TIMESTAMP는 UTC 변환 저장, 2038년 한계
참/거짓 BOOLEAN (= TINYINT(1)) (없음)
반정형 JSON JSON 함수 기반 인덱스로 검색 가속
열거 ENUM('A','B') CHECK 제약 값 추가 시 ALTER 필요
중요
문자셋은 반드시 utf8mb4를 사용한다. MySQL의 utf8(= utf8mb3)은 한 글자 최대 3바이트라 이모지 등 4바이트 문자를 저장하지 못한다. MySQL 8.0부터 기본값은 utf8mb4 / utf8mb4_0900_ai_ci이다.

4.2 테이블 만들기

CREATE DATABASE shop DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
USE shop;

CREATE TABLE customer (
    cust_id     BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    cust_nm     VARCHAR(100) NOT NULL,
    email       VARCHAR(200),
    grade_cd    VARCHAR(10)  NOT NULL DEFAULT 'NORMAL',
    attrs       JSON,
    created_at  DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (cust_id),
    UNIQUE KEY uk_customer_email (email)
) ENGINE=InnoDB COMMENT='고객';

CREATE TABLE orders (
    order_id    BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    cust_id     BIGINT UNSIGNED NOT NULL,
    order_dt    DATE           NOT NULL,
    amount      DECIMAL(12,2)  NOT NULL,
    PRIMARY KEY (order_id),
    KEY ix_orders_cust (cust_id, order_dt),
    CONSTRAINT fk_orders_cust FOREIGN KEY (cust_id) REFERENCES customer (cust_id),
    CONSTRAINT ck_orders_amt CHECK (amount >= 0)          -- 8.0.16부터 CHECK 실제 적용
) ENGINE=InnoDB;

4.3 자주 쓰는 SQL

-- 방금 생성된 AUTO_INCREMENT 값
INSERT INTO customer (cust_nm, email) VALUES ('홍길동', 'hong@example.com');
SELECT LAST_INSERT_ID();

-- UPSERT
INSERT INTO customer (cust_nm, email) VALUES ('홍길동', 'hong@example.com')
ON DUPLICATE KEY UPDATE cust_nm = VALUES(cust_nm);

-- 페이징
SELECT * FROM orders ORDER BY order_dt DESC LIMIT 40, 20;   -- 41번째부터 20건

-- JSON 조회
SELECT cust_nm FROM customer WHERE attrs->>'$.channel' = 'mobile';

-- CTE·윈도우 함수 (8.0+)
WITH t AS (SELECT cust_id, SUM(amount) AS amt FROM orders GROUP BY cust_id)
SELECT cust_id, amt, RANK() OVER (ORDER BY amt DESC) AS rnk FROM t;

4.4 Oracle 사용자를 위한 문법 대응표

Oracle MySQL 비고
SELECT 1 FROM DUAL SELECT 1 DUAL도 사용 가능
NVL(a, b) IFNULL(a, b), COALESCE(a, b)
SYSDATE NOW(), CURDATE() MySQL SYSDATE()는 호출 시각 (NOW는 문장 시작 시각)
ROWNUM <= 10 LIMIT 10
seq.NEXTVAL AUTO_INCREMENT 시퀀스 객체 없음
DECODE(a, 1, 'x', 'y') CASE, IF(a = 1, 'x', 'y')
TO_CHAR(dt, 'YYYY-MM-DD') DATE_FORMAT(dt, '%Y-%m-%d') 포맷 문자가 다르다
TO_DATE('20261104','YYYYMMDD') STR_TO_DATE('20261104', '%Y%m%d')
a || b CONCAT(a, b) MySQL의 ||는 기본적으로 논리 OR
MERGE INTO INSERT … ON DUPLICATE KEY UPDATE
CONNECT BY WITH RECURSIVE (8.0+)
MINUS EXCEPT (8.0.31+)
FULL OUTER JOIN 지원 안 함 → LEFT JOIN … UNION … RIGHT JOIN
'' = NULL '' ≠ NULL

5. InnoDB 내부 구조

5.1 메모리와 로그

 클라이언트 ──접속──▶ mysqld (하나의 프로세스) ──▶ 접속마다 스레드 1개
 ┌──────────── SQL 계층 ─────────────┐
 │ 파서 · 옵티마이저 · 실행기          │──▶ Binary Log (binlog: 복제·PITR용, 논리 변경 기록)
 └────────────────┬──────────────────┘
 ┌──────────── InnoDB 엔진 ──────────┐
 │ Buffer Pool (데이터·인덱스 페이지 캐시, 16KB) │
 │ Log Buffer ──▶ Redo Log (장애 복구용)        │
 │ Undo Log (MVCC 이전 버전, 롤백)              │
 │ Change Buffer · Adaptive Hash Index          │
 └───────────────────────────────────┘
 백그라운드 스레드: master · purge · page cleaner · I/O threads
변수 역할 출발점 (전용 서버 기준)
innodb_buffer_pool_size 버퍼 풀 크기 (가장 중요) 메모리의 50~70%
innodb_redo_log_capacity Redo 로그 전체 크기 (8.0.30+) 쓰기량에 맞춰 수 GB
innodb_flush_log_at_trx_commit 커밋 시 Redo 디스크 반영 방식 1 (안전, 기본값)
sync_binlog 커밋 시 binlog 동기화 1 (안전, 기본값)
max_connections 최대 접속 수 애플리케이션 커넥션 풀과 함께 설계
long_query_time / slow_query_log 느린 쿼리 기록 기준 1초 등으로 켜 두기

5.2 클러스터드 인덱스 — 가장 중요한 개념

InnoDB 저장 구조의 핵심
InnoDB 테이블의 데이터는 기본키(PK) 순서대로 B+Tree 리프에 저장된다 (클러스터드 인덱스). 보조 인덱스(Secondary Index)의 리프에는 ROWID가 아니라 PK 값이 들어 있어, 보조 인덱스로 찾은 뒤 PK로 한 번 더 찾아간다.
보조 인덱스
조건으로 PK 값 찾기
PK 인덱스
PK로 다시 탐색
데이터 행
클러스터드 리프에서 읽기
PK 설계 원칙 이유
짧은 값 (BIGINT 등) 모든 보조 인덱스에 PK가 복사되므로 PK가 길면 인덱스 전체가 커진다
증가하는 값 (AUTO_INCREMENT) 랜덤 값(UUID 문자열)은 중간 삽입으로 페이지 분할이 잦아진다
반드시 명시 PK가 없으면 InnoDB가 숨은 6바이트 행 ID를 만들어 쓴다
변경하지 않는 값 PK 변경은 행 이동 + 모든 보조 인덱스 갱신을 일으킨다

5.3 Redo Log와 Binlog

  • Redo Log — InnoDB 엔진의 장애 복구용 물리 로그 (Oracle Redo와 같은 역할).
  • Binary Log — 서버 계층의 논리 변경 기록. 복제와 시점 복구(PITR)에 쓰인다. 형식은 ROW(기본, 권장).
  • 두 로그는 내부 2단계 커밋으로 일관성을 맞춘다.

6. 인덱스와 실행계획

6.1 인덱스 기본

종류 설명 예
PRIMARY KEY 클러스터드 인덱스 (테이블 자체) PRIMARY KEY (order_id)
보조 인덱스 일반 B+Tree 인덱스 CREATE INDEX ix ON orders (cust_id, order_dt);
UNIQUE 중복 불가 보조 인덱스 UNIQUE KEY uk (email)
커버링 인덱스 필요한 컬럼이 모두 인덱스에 있어 PK 재탐색 생략 EXPLAIN Extra: Using index
함수 기반 인덱스 식 결과를 인덱싱 (8.0.13+) CREATE INDEX ix ON customer ((lower(email)));
FULLTEXT 전문 검색 (ngram 파서로 한글 지원) FULLTEXT KEY ft (title) WITH PARSER ngram
내림차순 인덱스 8.0부터 DESC 실제 적용 (order_dt DESC)
Online DDL
ALTER TABLE … ADD INDEX … , ALGORITHM=INPLACE, LOCK=NONE처럼 지정하면 대부분의 인덱스 추가를 운영 중 DML을 막지 않고 수행할 수 있다. 대용량 테이블은 gh-ost, pt-online-schema-change 같은 도구도 쓴다.

6.2 EXPLAIN 읽기

EXPLAIN
SELECT c.cust_nm, SUM(o.amount)
  FROM customer c JOIN orders o ON o.cust_id = c.cust_id
 WHERE o.order_dt >= CURDATE() - INTERVAL 30 DAY
 GROUP BY c.cust_nm;
컬럼 의미 주의해서 볼 값
table / id 접근 테이블과 실행 단위 위에서 아래 순서로 조인 (드라이빙 → 드리븐)
type 접근 방식 좋음 const → eq_ref → ref → range → index → ALL(풀스캔) 나쁨
possible_keys / key 후보 인덱스 / 실제 사용 인덱스 key가 NULL이면 인덱스 미사용
key_len 사용한 인덱스 길이 결합 인덱스의 몇 번째 컬럼까지 썼는지
rows 예상 읽기 행 수
filtered 조건 통과 예상 비율(%)
Extra 추가 정보 Using index(좋음), Using filesort, Using temporary(주의)
-- 실제 실행 시간·행 수까지 (8.0.18+) — Oracle의 ALLSTATS LAST와 비슷
EXPLAIN ANALYZE
SELECT * FROM orders WHERE cust_id = 1001 AND order_dt >= '2026-10-01';

-- 트리 형식 계획
EXPLAIN FORMAT=TREE SELECT ...;
인덱스를 못 타는 패턴은 Oracle과 같다 — 인덱스 컬럼 가공, 묵시적 형변환(문자 컬럼에 숫자 비교), 앞쪽 와일드카드 LIKE, 결합 인덱스 선두 컬럼 누락. 통계는 ANALYZE TABLE 테이블명;으로 갱신한다. → 인덱스 튜닝 심화

7. 트랜잭션과 락

격리 수준 특징 비고
READ UNCOMMITTED 커밋 전 데이터도 읽음 사용하지 않음
READ COMMITTED 커밋된 최신 데이터 읽기 Oracle 기본값과 같음
REPEATABLE READ 트랜잭션 시작 시점 스냅샷 유지 MySQL 기본값
SERIALIZABLE 읽기에도 공유 락
중요
REPEATABLE READ에서 범위 조건 UPDATE·DELETE·SELECT … FOR UPDATE는 행 사이 공간까지 잠그는 갭 락(Gap Lock) / 넥스트 키 락을 건다. 인덱스가 없는 컬럼으로 UPDATE하면 사실상 테이블 전체가 잠길 수 있으므로 조건 컬럼에 인덱스가 꼭 필요하다.
-- autocommit 기본값은 ON. 여러 문장을 묶으려면 명시적으로 시작
START TRANSACTION;
UPDATE orders SET amount = amount - 1000 WHERE order_id = 10;
COMMIT;

-- 락 대기 확인 (8.0+)
SELECT * FROM sys.innodb_lock_waits\G
SELECT * FROM performance_schema.data_locks LIMIT 20;

8. 사용자·권한

-- 사용자는 '이름'@'접속 호스트' 조합으로 구분된다
CREATE USER 'app_user'@'10.0.0.%' IDENTIFIED BY 'change_me';
GRANT SELECT, INSERT, UPDATE, DELETE ON shop.* TO 'app_user'@'10.0.0.%';

-- 역할(Role) 사용 (8.0+)
CREATE ROLE 'app_read';
GRANT SELECT ON shop.* TO 'app_read';
GRANT 'app_read' TO 'report_user'@'%';
SET DEFAULT ROLE ALL TO 'report_user'@'%';

SHOW GRANTS FOR 'app_user'@'10.0.0.%';
인증 플러그인
MySQL 8.0부터 기본 인증 방식은 caching_sha2_password이다. 오래된 클라이언트 드라이버는 접속 오류가 날 수 있으므로 드라이버를 최신으로 맞춘다.

9. 백업·복구·복제

방식 도구 특징 Oracle 대응
논리 백업 mysqldump SQL 문으로 덤프, 소규모 DB에 적합 Data Pump
논리 백업 (병렬) MySQL Shell util.dumpInstance() / loadDump() 병렬·압축, 대용량에 유리 Data Pump 병렬
물리 백업 Percona XtraBackup, MySQL Enterprise Backup 운영 중 온라인 물리 백업 RMAN
시점 복구 백업 + binlog 재적용 (mysqlbinlog) 원하는 시각·위치까지 복구 RMAN + Archive Log
복제 소스-레플리카 (binlog, GTID 권장) 읽기 분산, 대기 서버 Data Guard
고가용성 Group Replication / InnoDB Cluster 자동 장애 조치 RAC / Data Guard Broker
# 일관된 논리 백업 (InnoDB, 운영 중 락 최소화)
mysqldump -uroot -p --single-transaction --routines --triggers --events \
          --source-data=2 shop > shop.sql
mysql -uroot -p shop_new < shop.sql

# 시점 복구: 백업 이후 binlog를 특정 시각까지 재적용
mysqlbinlog --stop-datetime="2026-11-04 10:29:59" binlog.000123 | mysql -uroot -p

10. 모니터링 기본 쿼리

-- 실행 중인 세션 (Oracle V$SESSION)
SELECT id, user, host, db, command, time, state, LEFT(info, 60) AS query
  FROM information_schema.processlist
 WHERE command <> 'Sleep'
 ORDER BY time DESC;

-- 부하 상위 SQL (Oracle V$SQL) — sys 스키마 뷰
SELECT query, exec_count, total_latency, avg_latency, rows_examined_avg
  FROM sys.statement_analysis
 ORDER BY total_latency DESC
 LIMIT 10;

-- 테이블 크기
SELECT table_schema, table_name,
       ROUND((data_length + index_length) / 1024 / 1024) AS size_mb
  FROM information_schema.tables
 ORDER BY data_length + index_length DESC
 LIMIT 10;

-- 버퍼 풀 적중 관련 지표
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_read%';

11. 학습 커리큘럼 (10주)

설치 → SQL → InnoDB 구조 → 성능 → 운영 ·한 주에 이론 3시간 + 실습 3시간Oracle 경험자는 5주차(클러스터드 인덱스)에 특히 집중하세요.
주차 단계 주제 세부 내용 실습
1 기초 MySQL 소개와 설치 역사·에디션·MariaDB, Docker/패키지 설치, mysql 클라이언트, Workbench 실습 서버 구축, 기본 명령
2 논리 구조와 기본 SQL 데이터베이스=스키마, 시스템 DB, DDL/DML, autocommit 샘플 DB 생성
3 SQL 데이터 타입과 문자셋 숫자·문자·날짜, AUTO_INCREMENT, JSON, utf8mb4와 콜레이션 쇼핑몰 테이블 설계
4 고급 SQL CTE·WITH RECURSIVE, 윈도우 함수, UPSERT, Oracle 문법 차이 Oracle SQL 10개 변환
5 InnoDB 저장 구조 클러스터드 인덱스, 보조 인덱스, 페이지·페이지 분할, PK 설계 PK 종류별 INSERT 성능 비교
6 메모리와 로그 버퍼 풀, Redo·Undo·Binlog, MVCC, 주요 변수 my.cnf 분석
7 성능 인덱스와 EXPLAIN type·key·Extra 해석, 커버링 인덱스, EXPLAIN ANALYZE, 슬로 쿼리 로그 느린 SQL 3개 튜닝
8 트랜잭션과 락 격리 수준, 갭 락·넥스트 키 락, 데드락 분석, data_locks 락 대기 재현·분석
9 운영 보안과 모니터링 사용자@호스트, 역할, performance_schema, sys 스키마 읽기 전용 계정 설계
10 백업·복구·복제 mysqldump, MySQL Shell 덤프, XtraBackup, binlog PITR, GTID 복제 레플리카 구성 실습

12. 입문자 체크리스트

SELF CHECK
이 정도면 입문 완료
□ mysql 클라이언트로 접속해 DB·테이블 구조와 DDL을 확인할 수 있다
□ utf8mb4로 데이터베이스와 테이블을 만들 수 있다
□ InnoDB 클러스터드 인덱스와 보조 인덱스의 관계를 설명할 수 있다
□ EXPLAIN의 type, key, Extra를 보고 인덱스 사용 여부를 판단할 수 있다
□ REPEATABLE READ와 갭 락이 UPDATE에 주는 영향을 설명할 수 있다
□ mysqldump로 백업하고 복원할 수 있다

13. 용어집

용어 설명 Oracle 대응
스토리지 엔진 실제 데이터 저장·트랜잭션을 담당하는 계층 (InnoDB) (단일 엔진)
클러스터드 인덱스 PK 순서로 데이터를 저장하는 InnoDB 테이블 구조 IOT
보조 인덱스 PK 값을 가리키는 일반 인덱스 인덱스 (ROWID 대신 PK)
버퍼 풀 데이터·인덱스 페이지 캐시 Buffer Cache
Redo Log InnoDB 장애 복구용 로그 Redo Log
Binlog 복제·시점 복구용 논리 변경 로그 Archive Log (용도상)
GTID 전역 트랜잭션 ID, 복제 위치 관리 SCN (용도상)
갭 락 인덱스 레코드 사이 공간에 거는 락 (없음)
레플리카 복제 대상 서버 Standby DB
performance_schema 서버 성능 계측 정보 V$ 동적 성능 뷰

14. 참고 자료

이전 글PostgreSQL 입문
다음 글SQL 튜닝 입문