- Tác giả

- Name
- Nguyễn Đức Xinh
- Ngày xuất bản
- Ngày xuất bản
Cấu Hình Query Log Và Slow Query Log Trong MySQL: Server Tự Cài Và AWS RDS
Giới Thiệu
Bài Index trong MySQL và Tối ưu query với index đã chỉ ra cách dùng EXPLAIN/EXPLAIN ANALYZE để tìm điểm nghẽn khi bạn đã biết câu query nào đang chậm. Nhưng có một câu hỏi xuất hiện trước đó, thường xuyên hơn nhiều: làm sao biết câu query nào đang chạy, và câu nào đang chậm — khi bạn không có sẵn log của application, hoặc nghi ngờ có một job/cron/API nào đó đang âm thầm bắn ra query nặng?
Câu trả lời nằm ở hai loại log có sẵn trong MySQL:
- General Query Log: ghi lại mọi câu lệnh SQL server nhận được — dùng để audit, debug "ai đang query gì", nhưng chi phí hiệu năng cao nếu bật lâu dài.
- Slow Query Log: chỉ ghi lại những câu lệnh chạy chậm hơn một ngưỡng thời gian — chi phí thấp hơn nhiều, phù hợp để bật thường trực trên production.
Bài này tập trung vào phần thực dụng nhất: cách bật/tắt, cách chọn nơi xuất log (file hay table), và cách kiểm tra log — được trình bày song song cho hai kịch bản khác nhau hoàn toàn về vận hành:
- Server MySQL tự cài (self-managed): bạn có SSH, có quyền sửa
my.cnf, có quyền đọc file trên đĩa. - AWS RDS: MySQL được AWS quản lý, không có SSH, không có quyền sửa file cấu hình trực tiếp — mọi thay đổi tham số phải đi qua DB Parameter Group.
Đây là hai thế giới vận hành khác nhau, và một trong những lỗi phổ biến nhất của kỹ sư mới chuyển từ on-premise sang cloud là cố tìm file slow.log trên RDS — thứ không tồn tại theo cách bạn nghĩ.
Tổng Quan: General Query Log Và Slow Query Log Khác Nhau Thế Nào?
| Tiêu chí | General Query Log | Slow Query Log |
|---|---|---|
| Ghi lại gì | Tất cả câu lệnh SQL (SELECT, INSERT, UPDATE, connect, quit...) | Chỉ câu lệnh có thời gian chạy > long_query_time |
| Chi phí hiệu năng | Cao — mỗi query đều tốn thêm I/O ghi log | Thấp — chỉ ghi khi vượt ngưỡng |
| Dùng khi nào | Debug ngắn hạn: "app này đang gửi query gì xuống DB?" | Bật thường trực trên production để phát hiện query chậm |
| Biến điều khiển bật/tắt | general_log |
slow_query_log |
| Biến chọn nơi ghi | log_output (FILE / TABLE / FILE,TABLE) |
log_output (dùng chung với General Query Log) |
| Khuyến nghị bật lâu dài? | Không — chỉ bật tạm thời rồi tắt ngay | Có — chi phí thấp, giá trị chẩn đoán cao |
Điểm quan trọng cần nhớ: cả hai loại log dùng chung một biến log_output để quyết định ghi ra đâu. Đây là phần nhiều người bỏ qua, nên ta sẽ nói kỹ ở mục tiếp theo.
Hai Cách Xuất Log: FILE Và TABLE
MySQL cho phép chọn nơi ghi log qua biến log_output, với 3 giá trị:
SET GLOBAL log_output = 'FILE'; -- ghi ra file text trên đĩa (mặc định)
SET GLOBAL log_output = 'TABLE'; -- ghi vào bảng hệ thống mysql.general_log / mysql.slow_log
SET GLOBAL log_output = 'FILE,TABLE'; -- ghi ra cả hai (hiếm khi cần, tốn gấp đôi chi phí)
| Tiêu chí | log_output = FILE |
log_output = TABLE |
|---|---|---|
| Nơi lưu | File text (general.log, slow.log) trên đĩa server |
Bảng mysql.general_log, mysql.slow_log (storage engine CSV) |
| Cách đọc | tail -f, cat, công cụ phân tích như mysqldumpslow, pt-query-digest |
Truy vấn bằng SELECT ... WHERE ... như một bảng bình thường |
| Lọc theo điều kiện | Phải dùng công cụ ngoài (grep, script) | Dùng trực tiếp SQL: WHERE query_time > 5, WHERE db = 'shop'... |
| Hiệu năng ghi | Nhanh hơn (append file tuần tự) | Chậm hơn một chút (ghi vào bảng CSV, không có index) |
| Phù hợp với | Server tự cài, có quyền truy cập file hệ thống | AWS RDS (không có quyền đọc file trực tiếp), hoặc khi muốn SELECT nhanh mà không cần công cụ ngoài |
| Giới hạn | Cần logrotate để tránh đầy đĩa | Bảng CSV không có index → SELECT trên bảng lớn sẽ chậm, cần dọn dẹp định kỳ |
Đây chính là lý do phần "dùng table" trong tiêu đề bài viết quan trọng: trên AWS RDS, vì không có SSH vào filesystem, log_output = TABLE gần như là cách duy nhất để bạn tự truy vấn log bằng SQL mà không cần tải file log về qua console.
Phần 1: Cấu Hình Trên Server MySQL Tự Cài
Bước 1: Kiểm Tra Trạng Thái Hiện Tại
Trước khi đổi bất cứ thứ gì, luôn kiểm tra cấu hình đang chạy:
SHOW VARIABLES LIKE 'general_log%';
SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'log_output';
SHOW VARIABLES LIKE 'long_query_time';
Kết quả mẫu:
+------------------+----------------------------------+
| Variable_name | Value |
+------------------+----------------------------------+
| general_log | OFF |
| general_log_file | /var/lib/mysql/hostname.log |
| slow_query_log | OFF |
| log_output | FILE |
| long_query_time | 10.000000 |
+------------------+----------------------------------+
Bước 2: Bật General Query Log Bằng Cấu Hình Động (Không Cần Restart)
-- Chuyển output sang TABLE trước khi bật
SET GLOBAL log_output = 'TABLE';
-- Bật general query log
SET GLOBAL general_log = 'ON';
Chạy thử một vài câu lệnh SQL bất kỳ, rồi kiểm tra:
SELECT event_time, user_host, command_type, argument
FROM mysql.general_log
WHERE command_type = 'Query'
ORDER BY event_time DESC
LIMIT 200;
Giải thích:
SET GLOBALthay đổi giá trị ngay lập tức cho toàn bộ session mới, không cần restart MySQL — điểm khác biệt lớn so với sửamy.cnf(chỉ có hiệu lực sau khi restart).mysql.general_loglà bảng hệ thống, dùng storage engine CSV — chỉ hỗ trợSELECTvàTRUNCATE, không hỗ trợUPDATE/DELETEtừng dòng và không tạo được index.command_typecho biết loại sự kiện ghi log, không chỉ riêng câu SQL — lọcWHERE command_type = 'Query'để chỉ lấy các câu lệnh SQL thực sự (SELECT/INSERT/UPDATE/DELETE...), bỏ qua các sự kiện quản lý kết nối gây nhiễu.
Các giá trị command_type thường gặp:
| Giá trị | Ý nghĩa |
|---|---|
Query |
Một câu lệnh SQL thực thi trực tiếp (SELECT, INSERT, UPDATE, DELETE, DDL...) — giá trị cần lọc nhiều nhất khi audit query |
Connect |
Một client vừa kết nối tới server (ghi kèm user/host) |
Quit |
Client ngắt kết nối |
Init DB |
Client chuyển database làm việc (lệnh USE database_name) |
Prepare |
Chuẩn bị một prepared statement (PREPARE stmt FROM ...) |
Execute |
Thực thi một prepared statement đã chuẩn bị trước đó |
Close stmt |
Đóng một prepared statement |
Field List |
Client yêu cầu danh sách cột của một bảng (thường do driver/ORM tự động gọi) |
Statistics |
Client yêu cầu thông tin thống kê server (một số công cụ giám sát dùng lệnh này) |
Trong thực tế, gần như mọi phân tích "app đang query gì" chỉ cần quan tâm command_type = 'Query'; các giá trị còn lại chủ yếu phục vụ debug ở tầng kết nối (connection pool đóng/mở liên tục, driver gọi Init DB/Field List trước mỗi lần thao tác...).
Bước 3: Bật Bằng File Cấu Hình my.cnf (Bền Vững Qua Restart)
Cấu hình động ở Bước 2 sẽ mất khi MySQL restart. Muốn log tự bật lại mỗi lần server khởi động, cấu hình vào file my.cnf (thường ở /etc/mysql/my.cnf hoặc /etc/my.cnf):
[mysqld]
general_log = 1
general_log_file = /var/log/mysql/general.log
log_output = TABLE
Sau khi sửa, restart để áp dụng:
sudo systemctl restart mysql
Bước 4: Bật Slow Query Log
Slow Query Log là loại nên bật thường trực trên production vì chi phí thấp. Cấu hình động:
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1; -- ngưỡng: query > 1 giây coi là chậm
SET GLOBAL log_queries_not_using_indexes = 'ON'; -- ghi cả query không dùng index, dù nhanh
SET GLOBAL log_output = 'TABLE';
Hoặc bền vững trong my.cnf:
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = 1
log_output = TABLE
Giải thích các biến:
long_query_time: ngưỡng thời gian (đơn vị giây, hỗ trợ số thập phân như0.5) — query chạy lâu hơn giá trị này mới bị ghi log.log_queries_not_using_indexes: rất hữu ích khi audit — ghi lại cả những query nhanh nhưng đang full table scan, trước khi dữ liệu lớn lên khiến chúng trở thành query chậm thật sự.min_examined_row_limit: (tuỳ chọn) chỉ ghi log nếu query đã quét qua ít nhất N dòng — giúp lọc bớt noise từ những query "chậm" do lock wait chứ không phải do thiếu index.
Bước 5: Kiểm Tra Slow Query Log Khi Dùng TABLE
SELECT start_time, query_time, rows_examined, sql_text
FROM mysql.slow_log
ORDER BY start_time DESC
LIMIT 20;
Nếu dùng log_output = FILE, đọc trực tiếp file hoặc dùng công cụ chuyên dụng:
tail -f /var/log/mysql/slow.log
# Công cụ tổng hợp thống kê theo từng dạng query
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
# Công cụ mạnh hơn của Percona, gom nhóm theo query pattern
pt-query-digest /var/log/mysql/slow.log
Bước 6: Tắt Log Khi Không Cần Nữa
General Query Log không nên để bật lâu dài trên production — chỉ bật tạm thời để debug rồi tắt ngay:
SET GLOBAL general_log = 'OFF';
Với bảng log dùng CSV engine, nên dọn định kỳ để tránh phình to (bảng này không tự động xoay vòng như file):
TRUNCATE TABLE mysql.general_log;
TRUNCATE TABLE mysql.slow_log;
Phần 2: Cấu Hình Trên AWS RDS (Qua DB Parameter Group)
Vì Sao RDS Khác Hoàn Toàn Với Server Tự Cài?
AWS RDS là dịch vụ managed — AWS quản lý hệ điều hành, filesystem và tiến trình MySQL. Hệ quả trực tiếp:
- Không có SSH vào instance → không thể
sudo vim /etc/mysql/my.cnf. - Không có quyền
SUPERđầy đủ như self-managed → nhiềuSET GLOBALbị chặn hoặc phải qua stored procedure riêng của AWS. - Mọi tham số cấu hình server (tương đương nội dung
my.cnf) phải chỉnh qua DB Parameter Group — một tài nguyên tách rời, gán vào DB instance.
Vì lý do "không SSH được vào filesystem", log_output = TABLE trở thành lựa chọn quan trọng trên RDS: nó cho phép bạn SELECT trực tiếp bằng SQL client thay vì phải tải file log về qua console/CLI.
Bước 1: Tạo (Hoặc Xác Định) Custom DB Parameter Group
RDS không cho sửa Default Parameter Group (default.mysql8.0 chẳng hạn) — bạn bắt buộc phải tạo một Custom Parameter Group riêng nếu chưa có:
- Vào RDS Console → Parameter groups → Create parameter group.
- Chọn Parameter group family khớp đúng engine version đang dùng (ví dụ
mysql8.0). - Đặt tên, ví dụ
custom-mysql8-logging, rồi Create.
# Tương đương bằng AWS CLI
aws rds create-db-parameter-group \
--db-parameter-group-name custom-mysql8-logging \
--db-parameter-group-family mysql8.0 \
--description "Custom params for query/slow log"
Bước 2: Cấu Hình Các Tham Số Logging Trong Parameter Group
Vào parameter group vừa tạo → Edit parameters → tìm và chỉnh các tham số sau:
| Tham số | Giá trị đề xuất | Ghi chú |
|---|---|---|
general_log |
0 (mặc định) |
Chỉ bật 1 tạm thời khi cần debug, tắt lại ngay sau đó |
slow_query_log |
1 |
Nên bật thường trực trên production |
long_query_time |
1 (hoặc theo SLA của hệ thống) |
Ngưỡng tính là "chậm" |
log_output |
TABLE |
Bắt buộc dùng TABLE nếu muốn SELECT trực tiếp; RDS vẫn hỗ trợ FILE nếu bạn muốn xem qua console/CloudWatch |
log_queries_not_using_indexes |
1 |
Phát hiện sớm query full scan |
Bằng CLI:
aws rds modify-db-parameter-group \
--db-parameter-group-name custom-mysql8-logging \
--parameters \
"ParameterName=general_log,ParameterValue=0,ApplyMethod=immediate" \
"ParameterName=slow_query_log,ParameterValue=1,ApplyMethod=immediate" \
"ParameterName=long_query_time,ParameterValue=1,ApplyMethod=immediate" \
"ParameterName=log_output,ParameterValue=TABLE,ApplyMethod=immediate"
Lưu ý quan trọng: mỗi tham số trong RDS có cột Apply type là dynamic hoặc static. Tham số dynamic áp dụng ngay (immediate), không cần reboot; tham số static bắt buộc reboot instance mới có hiệu lực. general_log, slow_query_log, long_query_time, log_output thường là dynamic, nhưng luôn kiểm tra lại cột này trong console trước khi thao tác trên production để tránh bất ngờ.
Bước 3: Gán Parameter Group Vào DB Instance
Nếu instance đang dùng parameter group khác (ví dụ default), phải gán lại:
- Vào RDS Console → chọn DB instance → Modify.
- Ở mục Database options → DB parameter group, chọn
custom-mysql8-logging. - Chọn Apply immediately (áp dụng ngay) hoặc để áp dụng trong maintenance window kế tiếp.
- Continue → Modify DB Instance.
aws rds modify-db-instance \
--db-instance-identifier my-prod-db \
--db-parameter-group-name custom-mysql8-logging \
--apply-immediately
Nếu có tham số static trong nhóm thay đổi, RDS sẽ yêu cầu reboot — kiểm tra trạng thái parameter group trên console (pending-reboot là dấu hiệu cần reboot thủ công).
Bước 4: Kiểm Tra Log Trên RDS
Nếu dùng log_output = TABLE — kết nối bằng client SQL bất kỳ (không cần console AWS) và query trực tiếp:
SELECT start_time, query_time, rows_examined, sql_text
FROM mysql.slow_log
ORDER BY start_time DESC
LIMIT 20;
SELECT event_time, user_host, argument
FROM mysql.general_log
ORDER BY event_time DESC
LIMIT 20;
Nếu dùng log_output = FILE — không có SSH nên phải xem qua console hoặc CLI:
# Liệt kê các file log hiện có trên instance
aws rds describe-db-log-files --db-instance-identifier my-prod-db
# Tải một phần nội dung file log slow query
aws rds download-db-log-file-portion \
--db-instance-identifier my-prod-db \
--log-file-name slowquery/mysql-slowquery.log \
--output text > slow.log
Hoặc trên RDS Console → chọn instance → tab Logs & events → xem/tải trực tiếp.
Cách chuyên nghiệp hơn cho môi trường production: bật export log sang CloudWatch Logs để có khả năng lưu trữ dài hạn, tìm kiếm bằng CloudWatch Logs Insights, và tạo alarm tự động:
aws rds modify-db-instance \
--db-instance-identifier my-prod-db \
--cloudwatch-logs-export-configuration '{"EnableLogTypes":["slowquery","general"]}' \
--apply-immediately
Bước 5: Dọn Dẹp Bảng Log Trên RDS
Vì mysql.general_log/mysql.slow_log dùng CSV engine không có index, chúng sẽ ngày càng chậm khi phình to. Trên RDS, master user (tài khoản admin bạn tạo khi khởi tạo instance) có quyền được AWS cấp riêng để dọn các bảng hệ thống này:
TRUNCATE TABLE mysql.general_log;
TRUNCATE TABLE mysql.slow_log;
Nên lên lịch dọn định kỳ (ví dụ qua một scheduled event hoặc job ngoài) nếu để general_log bật trong thời gian dài, tránh bảng phình to ảnh hưởng đến dung lượng storage của instance.
So Sánh Nhanh: Self-Managed Vs AWS RDS
| Tiêu chí | Server Tự Cài | AWS RDS |
|---|---|---|
| Nơi cấu hình | File my.cnf hoặc SET GLOBAL trực tiếp |
DB Parameter Group (không sửa file trực tiếp được) |
| Cần restart khi nào | Chỉ khi sửa my.cnf; SET GLOBAL thì không |
Tuỳ tham số dynamic (không cần) hay static (cần reboot) |
| Đọc log dạng FILE | tail -f, SSH trực tiếp vào server |
Qua RDS Console (Logs & events), CLI, hoặc export CloudWatch Logs |
| Đọc log dạng TABLE | SELECT trực tiếp trên mysql.general_log/mysql.slow_log |
Giống hệt — SELECT trực tiếp, là cách được khuyến nghị vì không cần SSH |
| Quyền hạn | Toàn quyền SUPER, chỉnh mọi thứ |
Bị giới hạn bởi IAM + Parameter Group, một số biến không chỉnh được |
| Xoá bớt log tích luỹ | TRUNCATE, hoặc xoá/nén file + logrotate |
TRUNCATE bảng (được AWS cấp quyền đặc biệt), hoặc rotate file qua console |
Cảnh Báo Hiệu Năng Và Best Practices
- Không bao giờ để General Query Log bật vĩnh viễn trên production — mỗi câu SQL (kể cả
SELECTđơn giản) đều tốn thêm một lần ghi log, có thể làm tăng đáng kể latency dưới tải cao. Chỉ bật trong một khung thời gian ngắn để debug, rồi tắt ngay vàTRUNCATEbảng log. - Slow Query Log gần như luôn nên bật trên mọi môi trường production vì chi phí thấp và giá trị chẩn đoán cao — đây là nguồn dữ liệu đầu vào quan trọng nhất để tìm ra các query cần tối ưu bằng
EXPLAIN(xem thêm Tối ưu query với index). - Đặt
long_query_timephù hợp với SLA thực tế của hệ thống — quá thấp (ví dụ0.01) sẽ khiến log phình to vì ghi cả những query bình thường; quá cao (ví dụ10) sẽ bỏ sót nhiều vấn đề trước khi chúng trở nên nghiêm trọng. Giá trị0.5–2giây là điểm khởi đầu hợp lý cho hầu hết ứng dụng web. - Khi dùng
log_output = TABLE, luôn có kế hoạch dọn dẹp (TRUNCATEđịnh kỳ) — bảng CSV không có index nên càng lớn càng chậm khiSELECT, đặc biệt trên RDS nơi tài nguyên I/O được chia sẻ theo instance class. - Trên RDS, ưu tiên export log sang CloudWatch Logs cho môi trường production thật sự — nó tách biệt việc lưu trữ log ra khỏi resource của DB instance, hỗ trợ tìm kiếm mạnh hơn (CloudWatch Logs Insights) và giữ log ngay cả khi bảng
mysql.slow_logbịTRUNCATE.
Checklist Cấu Hình Query Log Và Slow Query Log
- [ ] Đã xác định đúng môi trường (self-managed hay AWS RDS) trước khi chọn cách cấu hình?
- [ ]
long_query_timeđã được đặt phù hợp với SLA thực tế, chưa dùng giá trị mặc định (10giây, thường quá cao)? - [ ]
log_outputđã chọn đúng —FILEnếu có SSH và dùng công cụ nhưpt-query-digest,TABLEnếu cầnSELECTtrực tiếp hoặc đang chạy trên RDS? - [ ] General Query Log chỉ bật tạm thời để debug, đã có kế hoạch tắt lại và
TRUNCATEsau khi dùng xong? - [ ] Trên RDS, đã tạo Custom Parameter Group riêng (không cố sửa default) và gán đúng vào instance?
- [ ] Đã kiểm tra tham số nào là
static(cần reboot) trước khi apply trên production để tránh downtime bất ngờ? - [ ] Đã cân nhắc export log sang CloudWatch Logs cho môi trường production trên RDS?
- [ ] Có job/lịch dọn dẹp định kỳ cho
mysql.general_log/mysql.slow_logđể tránh phình dung lượng?
Kết Luận
Query Log và Slow Query Log là hai công cụ quan sát cơ bản nhưng thường bị bỏ qua cho đến khi có sự cố xảy ra. Điểm mấu chốt cần nhớ: General Query Log dùng để debug ngắn hạn, Slow Query Log nên bật thường trực; và cách xuất log (FILE hay TABLE) không chỉ là chi tiết kỹ thuật — nó quyết định bạn sẽ đọc log bằng cách nào, đặc biệt quan trọng khi chuyển từ server tự cài (có SSH, có file) sang AWS RDS (không SSH, phải qua Parameter Group và thường dùng TABLE hoặc CloudWatch Logs).
Sau khi đã bật đúng log và thu thập được danh sách query chậm, bước tiếp theo là quay lại bài Tối ưu query với index để áp dụng EXPLAIN ANALYZE và composite index đúng cách cho từng query cụ thể được phát hiện qua Slow Query Log.
