MySQL 데이터베이스를 사용하는 웹사이트가 처음에는 빠르게 작동하다가 데이터가 쌓이면서 갑자기 느려지는 경우가 있습니다.
페이지가 늦게 열리거나 관리자 화면에서 검색 결과가 오래 걸리고, 특정 시간대에 서버 CPU 사용률이 높아진다면 데이터베이스의 느린 쿼리(Slow Query)를 확인해볼 필요가 있습니다.
특히 리눅스 서버에서 MySQL을 운영한다면 단순히 서버 사양을 높이는 것보다 어떤 SQL 쿼리가 실제로 시간을 많이 사용하는지 먼저 확인하는 것이 중요합니다.
MySQL에는 이런 문제를 찾기 위한 기능으로 Slow Query Log(느린 쿼리 로그)가 제공됩니다.
이번 글에서는 MySQL Slow Query Log의 개념부터 설정 방법, 느

린 쿼리 확인 방법, EXPLAIN을 이용한 분석, 인덱스 점검, 성능 개선의 기본 원칙까지 초보자도 따라 할 수 있도록 정리해보겠습니다.
1. MySQL Slow Query Log란?
Slow Query Log는 MySQL에서 실행 시간이 오래 걸리는 SQL 쿼리를 기록하는 로그입니다.
예를 들어 다음과 같은 쿼리가 있다고 가정해보겠습니다.
SELECT *
FROM orders
WHERE customer_name = '홍길동';
데이터가 수천 건 정도라면 빠르게 실행될 수 있습니다.
하지만 데이터가 수백만 건으로 늘어나면 같은 SQL이라도 실행 시간이 크게 증가할 수 있습니다.
이때 Slow Query Log를 활성화하면 MySQL이 설정한 기준보다 오래 걸리는 쿼리를 기록합니다.
즉,
사용자 요청
↓
SQL 실행
↓
실행 시간이 너무 오래 걸림
↓
Slow Query Log 기록
↓
느린 쿼리 분석
↓
인덱스·SQL 구조 개선
이라는 방식으로 문제를 찾을 수 있습니다.
2. 왜 느린 쿼리를 찾아야 할까?
데이터베이스 성능이 떨어지면 단순히 SQL 하나만 느려지는 것이 아닙니다.
느린 쿼리가 반복적으로 실행되면 다음과 같은 문제가 발생할 수 있습니다.
- 웹페이지 응답 속도 저하
- CPU 사용량 증가
- 디스크 I/O 증가
- 데이터베이스 연결 증가
- 서버 부하 증가
- 사용자 요청 대기시간 증가
- 웹서비스 전체 성능 저하
특히 같은 느린 쿼리가 많은 사용자의 요청에 의해 반복 실행된다면 작은 문제도 서버 전체의 성능 문제로 커질 수 있습니다.
따라서 서버가 느려졌을 때는 무작정 CPU나 메모리를 늘리기보다 어떤 SQL이 병목을 만드는지 확인하는 것이 첫 번째 단계입니다.
3. Slow Query Log 활성화 여부 확인
먼저 MySQL에 접속합니다.
mysql -u root -p
접속한 후 다음 명령어를 실행합니다.
SHOW VARIABLES LIKE 'slow_query_log';
결과가 다음과 같이 나올 수 있습니다.
slow_query_log OFF
OFF라면 Slow Query Log가 비활성화된 상태입니다.
활성화되어 있다면:
slow_query_log ON
으로 표시됩니다.
4. 느린 쿼리 기준 시간 확인하기
Slow Query Log가 활성화되어 있다고 해서 모든 SQL을 기록하는 것은 아닙니다.
MySQL에서는 long_query_time이라는 설정값을 기준으로 느린 쿼리를 판단할 수 있습니다.
확인 방법은 다음과 같습니다.
SHOW VARIABLES LIKE 'long_query_time';
예를 들어:
long_query_time 10.000000
이라면 기본적으로 10초 이상 실행된 쿼리를 느린 쿼리로 기록하도록 설정된 것입니다.
웹서비스에서는 10초가 너무 긴 기준일 수 있기 때문에 서버 환경에 따라 더 낮은 값으로 설정해 분석할 수 있습니다.
5. Slow Query Log 저장 위치 확인하기
로그가 어디에 저장되는지도 확인해야 합니다.
SHOW VARIABLES LIKE 'slow_query_log_file';
예를 들어:
/var/lib/mysql/mysql-slow.log
처럼 표시될 수 있습니다.
또는 MySQL 설정에 따라 다른 위치에 저장될 수 있습니다.
따라서 특정 경로를 무조건 가정하기보다는 현재 서버에서 실제 설정값을 확인하는 것이 중요합니다.
6. Slow Query Log 활성화하기
운영 환경에서는 설정 변경 전에 현재 설정을 확인하는 것이 좋습니다.
MySQL에서 다음과 같이 실행할 수 있습니다.
SET GLOBAL slow_query_log = 'ON';
그리고 기준 시간을 설정할 수 있습니다.
예를 들어 2초 이상 걸리는 쿼리를 분석하려면:
SET GLOBAL long_query_time = 2;
현재 값을 다시 확인합니다.
SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'long_query_time';
다만 SET GLOBAL로 변경한 값은 MySQL 재시작 후 유지되지 않을 수 있습니다.
서버 재시작 이후에도 적용하려면 MySQL 설정 파일에 영구적으로 설정해야 합니다.
7. MySQL 설정 파일에 Slow Query Log 설정하기
리눅스 환경에서는 MySQL 설정 파일이 설치 방식과 배포판에 따라 위치가 다를 수 있습니다.
대표적으로 다음과 같은 위치가 사용됩니다.
/etc/my.cnf
/etc/mysql/my.cnf
/etc/mysql/mysql.conf.d/mysqld.cnf
현재 서버의 설치 환경을 먼저 확인하는 것이 좋습니다.
설정 파일의 [mysqld] 영역에 다음과 같은 설정을 추가할 수 있습니다.
[mysqld]
slow_query_log = ON
long_query_time = 2
slow_query_log_file = /var/log/mysql/mysql-slow.log
설정 파일을 변경했다면 MySQL 서비스를 재시작해야 할 수 있습니다.
Ubuntu 계열에서 일반적으로:
sudo systemctl restart mysql
RHEL 계열이나 설치 방식에 따라 서비스 이름이 mysqld일 수도 있습니다.
sudo systemctl restart mysqld
따라서 실제 서버의 서비스 이름을 먼저 확인하는 것이 좋습니다.
8. 너무 낮은 기준 시간을 설정하면 안 되는 이유
느린 쿼리를 찾겠다고 long_query_time을 무조건 아주 낮게 설정하는 것은 좋은 방법이 아닙니다.
예를 들어:
long_query_time = 0
처럼 설정하면 거의 모든 쿼리가 로그에 기록될 수 있습니다.
그러면 로그 파일이 빠르게 커지고 디스크 공간을 많이 사용할 수 있습니다.
따라서 처음에는:
1~2초
정도의 기준으로 테스트한 후 서버 환경과 서비스 특성에 맞게 조정하는 방법을 고려할 수 있습니다.
로그는 많이 기록하는 것보다 필요한 정보를 효율적으로 수집하는 것이 중요합니다.
9. Slow Query Log 확인하기
로그 파일 위치를 확인했다면 리눅스에서 다음과 같이 확인할 수 있습니다.
sudo tail -f /var/log/mysql/mysql-slow.log
최근 기록을 확인하려면:
sudo tail -n 100 /var/log/mysql/mysql-slow.log
파일 전체가 너무 크다면 less를 사용할 수도 있습니다.
sudo less /var/log/mysql/mysql-slow.log
10. Slow Query Log에서 무엇을 봐야 할까?
Slow Query Log에는 쿼리 실행 시간과 관련된 정보가 기록됩니다.
대표적으로 다음과 같은 항목을 확인할 수 있습니다.
Query_time
Lock_time
Rows_sent
Rows_examined
특히 중요한 항목은 Query_time과 Rows_examined입니다.
Query_time
SQL이 실행되는 데 걸린 시간을 나타냅니다.
Rows_examined
쿼리 처리 과정에서 MySQL이 확인한 행의 수를 나타냅니다.
예를 들어 결과는 몇 건밖에 나오지 않았는데:
Rows_sent: 10
Rows_examined: 5000000
처럼 나온다면 많은 데이터를 검색한 뒤 일부 결과만 반환했을 가능성을 의심할 수 있습니다.
11. 느린 쿼리를 발견했다면 EXPLAIN 사용하기
Slow Query Log에서 문제가 되는 SQL을 찾았다면 다음 단계는 실행 계획을 확인하는 것입니다.
MySQL에서는 EXPLAIN 명령어를 사용할 수 있습니다.
예를 들어:
EXPLAIN
SELECT *
FROM orders
WHERE customer_id = 100;
실행하면 MySQL이 해당 SQL을 어떤 방식으로 처리할지에 대한 정보를 보여줍니다.
이 정보를 이용하면 인덱스를 사용하는지, 많은 데이터를 검사하는지 등을 분석할 수 있습니다.
12. EXPLAIN에서 중요한 항목
처음 EXPLAIN을 접한다면 모든 항목을 외울 필요는 없습니다.
먼저 다음 항목부터 확인하면 됩니다.
항목의미
| type | 테이블 접근 방식 |
| possible_keys | 사용할 가능성이 있는 인덱스 |
| key | 실제 사용한 인덱스 |
| rows | 예상 검사 행 수 |
| Extra | 추가 실행 정보 |
특히 key가 NULL이고 대량의 데이터를 처리하는 쿼리라면 인덱스 사용 여부를 검토할 필요가 있습니다.
다만 key=NULL 자체가 무조건 성능 문제라는 뜻은 아닙니다.
데이터 양이 적거나 전체 테이블을 읽는 것이 더 효율적인 경우도 있기 때문입니다.
13. 인덱스가 중요한 이유
느린 SQL을 개선할 때 가장 자주 확인하는 부분 중 하나가 인덱스(Index)입니다.
예를 들어 다음과 같은 테이블이 있다고 가정해보겠습니다.
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(255)
);
다음 SQL을 자주 실행한다고 가정합니다.
SELECT *
FROM users
WHERE email = 'user@example.com';
email을 기준으로 검색하는 요청이 많고 데이터가 매우 많다면 적절한 인덱스를 검토할 수 있습니다.
CREATE INDEX idx_users_email
ON users(email);
이후 EXPLAIN을 이용해 실행 계획이 어떻게 달라졌는지 확인할 수 있습니다.
14. SELECT *를 무조건 사용하는 습관 줄이기
다음과 같은 SQL은 간단하고 편리합니다.
SELECT *
FROM users
WHERE id = 10;
하지만 실제 서비스에서는 필요한 컬럼만 지정하는 것이 더 명확합니다.
예:
SELECT id, name, email
FROM users
WHERE id = 10;
특히 컬럼이 많거나 데이터 크기가 큰 테이블에서는 불필요한 데이터를 가져오는 작업을 줄이는 것이 도움이 될 수 있습니다.
15. WHERE 조건이 없는 대량 조회 주의하기
다음과 같은 쿼리를 생각해보겠습니다.
SELECT *
FROM orders;
데이터가 수백만 건이라면 많은 데이터를 읽어야 할 수 있습니다.
관리자 페이지나 API에서 모든 데이터를 한 번에 가져오는 구조라면 성능 문제가 발생할 가능성이 있습니다.
이런 경우 페이지 단위 조회나 필요한 조건을 적용하는 방식을 검토할 수 있습니다.
예:
SELECT id, order_date, customer_id
FROM orders
ORDER BY order_date DESC
LIMIT 100;
16. LIMIT을 활용한 데이터 조회
사용자 화면에서 수천 건의 데이터를 한 번에 보여줄 필요가 없다면 LIMIT을 사용할 수 있습니다.
예:
SELECT *
FROM orders
ORDER BY id DESC
LIMIT 50;
이렇게 하면 한 번에 가져오는 데이터 양을 제한할 수 있습니다.
다만 대용량 데이터에서 페이지 번호가 뒤로 갈수록 OFFSET 방식의 성능 문제가 발생할 수 있으므로 서비스 규모가 커지면 키셋 페이지네이션(Keyset Pagination) 같은 방법도 검토할 수 있습니다.
17. LIKE 검색도 주의해야 한다
다음과 같은 검색을 자주 사용하는 경우:
SELECT *
FROM users
WHERE name LIKE '%길동%';
앞부분에 %가 붙어 있으면 일반적인 B-Tree 인덱스를 효율적으로 활용하기 어려울 수 있습니다.
반면:
WHERE name LIKE '길동%'
과 같은 형태는 상황에 따라 인덱스를 활용할 가능성이 있습니다.
따라서 검색 기능이 느리다면 LIKE 조건과 인덱스 사용 여부를 함께 확인하는 것이 좋습니다.
18. Slow Query Log와 EXPLAIN을 함께 사용하기
느린 쿼리 성능 개선은 다음 순서로 진행하면 이해하기 쉽습니다.
1. Slow Query Log 활성화
↓
2. 느린 SQL 확인
↓
3. Query_time 확인
↓
4. Rows_examined 확인
↓
5. EXPLAIN 실행
↓
6. 인덱스 및 SQL 구조 검토
↓
7. 수정 후 다시 테스트
중요한 것은 SQL을 수정한 뒤 실제 성능이 좋아졌는지 다시 확인하는 것입니다.
19. MySQL 상태 확인 명령어
느린 쿼리 외에도 현재 MySQL 상태를 확인하는 명령어를 알아두면 좋습니다.
현재 실행 중인 쿼리 확인:
SHOW PROCESSLIST;
좀 더 자세한 정보를 확인하려면:
SHOW FULL PROCESSLIST;
현재 데이터베이스 목록:
SHOW DATABASES;
테이블 목록:
SHOW TABLES;
현재 설정값 확인:
SHOW VARIABLES LIKE 'slow%';
20. Performance Schema도 활용할 수 있다
최근 MySQL 환경에서는 Slow Query Log 외에도 Performance Schema를 이용해 SQL 성능 정보를 분석할 수 있습니다.
예를 들어 어떤 SQL이 많이 실행되는지, 실행 시간이 얼마나 되는지 등을 확인하는 데 활용할 수 있습니다.
다만 Performance Schema는 처음 접하는 사용자에게는 조금 복잡할 수 있기 때문에 서버 성능 분석을 시작한다면:
Slow Query Log
→ EXPLAIN
→ 인덱스 확인
→ SQL 개선
순서로 접근하는 것이 이해하기 쉽습니다.
21. 로그 파일 관리도 중요하다
Slow Query Log를 활성화하면 로그 파일이 계속 커질 수 있습니다.
따라서 운영 서버에서는 로그 로테이션(log rotation)도 함께 고려해야 합니다.
리눅스에서는 logrotate를 이용해 오래된 로그를 압축하거나 삭제하는 방식으로 관리할 수 있습니다.
예를 들어:
mysql-slow.log
mysql-slow.log.1
mysql-slow.log.2.gz
처럼 오래된 로그를 관리할 수 있습니다.
로그 관리가 제대로 되지 않으면 디스크 공간 부족으로 서버 장애가 발생할 수도 있으므로 정기적으로 로그 크기를 확인하는 것이 좋습니다.
22. 디스크 사용량 확인하기
Slow Query Log가 너무 커졌는지 확인하려면:
df -h
를 사용합니다.
MySQL 로그 디렉터리의 크기를 확인하려면 환경에 맞는 경로에서:
du -sh /var/log/mysql
처럼 확인할 수 있습니다.
특정 로그 파일 크기:
ls -lh /var/log/mysql/
서버에서 로그를 활성화한 뒤에는 로그 크기와 디스크 사용량을 함께 모니터링하는 습관이 중요합니다.
23. 느린 쿼리를 무조건 인덱스로 해결하면 안 되는 이유
느린 SQL을 발견했다고 해서 무조건 인덱스를 추가하는 것은 좋은 방법이 아닙니다.
인덱스는 검색 속도를 높이는 데 도움이 될 수 있지만 추가적인 저장 공간을 사용하고 INSERT, UPDATE, DELETE 작업에도 영향을 줄 수 있습니다.
따라서 다음을 함께 고려해야 합니다.
쿼리 구조
+
데이터 양
+
검색 조건
+
인덱스
+
실행 빈도
+
읽기/쓰기 비율
즉, 실행 계획을 확인한 후 필요한 인덱스를 선택하는 것이 중요합니다.
24. 운영 서버에서 주의할 점
운영 중인 MySQL 서버에서 성능 설정을 변경할 때는 주의해야 합니다.
특히:
- Slow Query Log를 무조건 장시간 활성화하지 않기
- 너무 낮은 long_query_time 설정 피하기
- 로그 저장 공간 확인하기
- 설정 변경 전 기존 설정 백업하기
- 인덱스 추가 전 테이블 크기 확인하기
- 운영 데이터에 직접 테스트 SQL 실행하지 않기
- 성능 개선 전후를 비교하기
등을 고려해야 합니다.
성능 개선의 핵심은 추측이 아니라 측정입니다.
25. MySQL 느린 쿼리 점검 명령어 모음
Slow Query Log 확인
SHOW VARIABLES LIKE 'slow_query_log';
느린 쿼리 기준 시간 확인
SHOW VARIABLES LIKE 'long_query_time';
로그 위치 확인
SHOW VARIABLES LIKE 'slow_query_log_file';
Slow Query Log 활성화
SET GLOBAL slow_query_log = 'ON';
기준 시간 변경
SET GLOBAL long_query_time = 2;
실행 중인 SQL 확인
SHOW FULL PROCESSLIST;
실행 계획 확인
EXPLAIN SELECT * FROM users WHERE id = 10;
26. 초보자를 위한 실전 점검 예제
웹사이트의 orders 테이블 검색이 느려졌다고 가정해보겠습니다.
먼저 Slow Query Log에서 해당 SQL을 찾습니다.
SELECT *
FROM orders
WHERE customer_id = 1000;
그다음 실행 계획을 확인합니다.
EXPLAIN
SELECT *
FROM orders
WHERE customer_id = 1000;
key, rows, type 등의 값을 확인합니다.
만약 적절한 인덱스가 없고 데이터가 매우 많다면:
CREATE INDEX idx_orders_customer_id
ON orders(customer_id);
를 검토할 수 있습니다.
그리고 다시:
EXPLAIN
SELECT *
FROM orders
WHERE customer_id = 1000;
을 실행하여 실행 계획이 개선되었는지 확인합니다.
마지막으로 실제 애플리케이션에서 응답 시간이 좋아졌는지도 확인해야 합니다.
마무리
MySQL 서버가 느려졌을 때 단순히 서버의 CPU나 메모리를 늘리는 것만이 해결책은 아닙니다.
실제로는 느린 SQL 쿼리 하나가 반복적으로 실행되면서 데이터베이스 전체의 성능을 떨어뜨리는 경우도 있습니다.
이럴 때 가장 기본적으로 활용할 수 있는 기능이 MySQL Slow Query Log입니다.
핵심적인 점검 순서는 다음과 같습니다.
Slow Query Log 활성화
↓
느린 SQL 찾기
↓
Query_time 확인
↓
Rows_examined 확인
↓
EXPLAIN 실행
↓
인덱스 및 SQL 구조 점검
↓
수정
↓
성능 재측정
특히 Slow Query Log → EXPLAIN → 인덱스 검토의 흐름을 익혀두면 리눅스 서버에서 MySQL 성능 문제를 분석할 때 큰 도움이 됩니다.
또한 로그를 활성화한 뒤에는 로그 파일이 계속 증가할 수 있으므로 logrotate 등을 이용한 로그 관리와 디스크 공간 관리도 함께 진행하는 것이 중요합니다.
결국 MySQL 성능 개선에서 가장 중요한 원칙은 무작정 설정을 변경하는 것이 아니라 실제로 느린 쿼리를 찾아 원인을 측정하고 개선하는 것입니다.