一、慢查询诊断与定位
1. 开启慢查询日志
sql
复制
下载
-- MySQL 慢查询配置
-- 查看当前配置
SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'long_query_time';
SHOW VARIABLES LIKE 'log_queries_not_using_indexes';
-- 开启慢查询日志(配置文件 my.cnf)
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2 -- 超过2秒的查询
log_queries_not_using_indexes = 1 -- 记录未使用索引的查询
log_throttle_queries_not_using_indexes = 10 -- 限制每分钟记录数量
min_examined_row_limit = 100 -- 最少扫描行数
-- 动态开启(无需重启)
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
SET GLOBAL slow_query_log_file = '/tmp/slow.log';
2. 分析慢查询日志
bash
复制
下载
# 1. 使用mysqldumpslow工具(MySQL自带)
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
# -s t: 按总时间排序
# -t 10: 显示前10条
# 2. 使用pt-query-digest(Percona Toolkit)
pt-query-digest /var/log/mysql/slow.log
# 生成详细报告,包括:
# - 查询执行时间分布
# - 表锁定时间
# - 行扫描统计
# - 索引使用情况
# 3. 输出示例分析
# Time: 2024-01-15T10:30:00.123456Z
# User@Host: user[app] @ [192.168.1.100]
# Query_time: 5.123456 Lock_time: 0.001234 Rows_sent: 10 Rows_examined: 1000000
# SET timestamp=1705300200;
# SELECT * FROM orders WHERE user_id = 123 AND status = 'pending' ORDER BY created_at DESC;
3. 实时监控与诊断
sql
复制
下载
-- 1. 查看当前执行中的慢查询
SHOW PROCESSLIST;
-- 重点关注:
-- Command: Query
-- Time: 执行时间
-- State: 执行状态
-- Info: SQL语句
-- 2. 使用performance_schema
SELECT * FROM performance_schema.events_statements_summary_by_digest
WHERE SUM_TIMER_WAIT > 1000000000 -- 超过1秒
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 10;
-- 3. 使用sys schema(MySQL 5.7+)
-- 查看最耗时的语句
SELECT * FROM sys.statements_with_runtimes_in_95th_percentile;
-- 查看全表扫描的语句
SELECT * FROM sys.statements_with_full_table_scans;
-- 查看使用临时表的语句
SELECT * FROM sys.statements_with_temp_tables;
二、EXPLAIN深度解析
1. EXPLAIN各字段含义
sql
复制
下载
-- 基本用法
EXPLAIN FORMAT=JSON
SELECT * FROM orders o
JOIN users u ON o.user_id = u.id
WHERE u.email LIKE '%@gmail.com'
ORDER BY o.created_at DESC
LIMIT 100;
-- 关键字段解读:
/*
id: 查询序列号(子查询顺序)
select_type: 查询类型(SIMPLE/PRIMARY/SUBQUERY等)
table: 访问的表
partitions: 匹配的分区
type: 访问类型(重要!性能指标)
possible_keys: 可能使用的索引
key: 实际使用的索引
key_len: 索引长度
ref: 列与索引的比较
rows: 估计要检查的行数
filtered: 条件过滤的百分比
Extra: 额外信息
*/
-- 使用EXPLAIN ANALYZE(MySQL 8.0.18+)
-- 显示实际执行时间和计划
EXPLAIN ANALYZE
SELECT * FROM users WHERE age > 30;
2. type字段性能等级
sql
复制
下载
-- 从最佳到最差排序:
-- 1. system: 系统表,一行记录
-- 2. const: 主键或唯一索引等值查询
EXPLAIN SELECT * FROM users WHERE id = 1;
-- type: const, rows: 1
-- 3. eq_ref: 唯一索引关联
EXPLAIN SELECT * FROM orders o
JOIN users u ON o.user_id = u.id -- u.id是主键
WHERE o.status = 'paid';
-- 4. ref: 非唯一索引等值查询
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
-- email有非唯一索引
-- 5. range: 索引范围查询
EXPLAIN SELECT * FROM users WHERE age BETWEEN 20 AND 30;
EXPLAIN SELECT * FROM orders WHERE created_at > '2024-01-01';
-- 6. index: 全索引扫描
EXPLAIN SELECT COUNT(*) FROM users;
-- 如果count(id)且有索引
-- 7. ALL: 全表扫描(需要优化)
EXPLAIN SELECT * FROM users WHERE name LIKE '%John%';
3. Extra字段关键信息
sql
复制
下载
-- 需要关注的Extra信息:
-- 1. Using index: 覆盖索引(性能好)
EXPLAIN SELECT id, name FROM users WHERE age > 20;
-- id, name, age都在索引中
-- 2. Using where: 在存储引擎层过滤
-- 3. Using temporary: 使用临时表(需要优化)
EXPLAIN SELECT DISTINCT department FROM employees
ORDER BY salary DESC;
-- 4. Using filesort: 文件排序(需要优化)
EXPLAIN SELECT * FROM users ORDER BY name;
-- 5. Using join buffer: 使用连接缓冲区
-- 6. Impossible WHERE: WHERE条件不可能满足
-- 7. Select tables optimized away: 优化器已优化
三、索引优化策略
1. 索引设计原则
sql
复制
下载
-- 1. 最左前缀原则
CREATE INDEX idx_name_age_city ON users(name, age, city);
-- 能使用索引的查询:
SELECT * FROM users WHERE name = 'John';
SELECT * FROM users WHERE name = 'John' AND age = 30;
SELECT * FROM users WHERE name = 'John' AND age = 30 AND city = 'NYC';
-- 不能使用索引的查询:
SELECT * FROM users WHERE age = 30; -- 跳过了name
SELECT * FROM users WHERE city = 'NYC'; -- 跳过了前两列
-- 2. 索引列选择
-- 选择区分度高的列(基数大)
SELECT COUNT(DISTINCT status) / COUNT(*) FROM orders;
-- 值越接近1,区分度越高
-- 3. 覆盖索引优化
-- 创建覆盖索引
CREATE INDEX idx_covering ON orders(user_id, status, amount, created_at);
-- 查询可以直接使用索引
EXPLAIN SELECT user_id, status, amount
FROM orders
WHERE user_id = 123 AND status = 'paid';
-- Extra: Using index
2. 避免索引失效场景
sql
复制
下载
-- 1. 不要在索引列上运算
-- 错误:索引失效
SELECT * FROM users WHERE YEAR(created_at) = 2024;
SELECT * FROM users WHERE age + 1 > 30;
-- 正确:使用范围查询
SELECT * FROM users WHERE created_at >= '2024-01-01'
AND created_at < '2025-01-01';
-- 2. 避免使用NOT、!=、<>、NOT IN
-- 可能无法使用索引
SELECT * FROM users WHERE status != 'active';
-- 3. 小心使用OR
-- OR可能导致索引失效
SELECT * FROM users WHERE name = 'John' OR age = 30;
-- 优化:使用UNION
SELECT * FROM users WHERE name = 'John'
UNION
SELECT * FROM users WHERE age = 30;
-- 4. 注意LIKE查询
-- 前导通配符导致索引失效
SELECT * FROM users WHERE name LIKE '%John%'; -- 全表扫描
SELECT * FROM users WHERE name LIKE 'John%'; -- 可以使用索引
-- 5. 注意数据类型转换
-- 隐式类型转换导致索引失效
SELECT * FROM users WHERE phone = 13800138000; -- phone是varchar
-- 正确:
SELECT * FROM users WHERE phone = '13800138000';
3. 复合索引优化技巧
sql
复制
下载
-- 1. 等值查询列在前,范围查询列在后
-- 好的设计:
CREATE INDEX idx_user_status_time ON orders(user_id, status, created_at);
SELECT * FROM orders
WHERE user_id = 123
AND status = 'paid'
AND created_at > '2024-01-01'; -- 范围查询在最后
-- 2. ORDER BY优化
-- 索引顺序与ORDER BY一致,避免filesort
CREATE INDEX idx_status_created ON orders(status, created_at);
-- 可以使用索引排序
SELECT * FROM orders
WHERE status = 'paid'
ORDER BY created_at DESC;
-- 3. 包含所有WHERE和ORDER BY列
CREATE INDEX idx_complete ON orders(
user_id,
status,
created_at,
amount
);
SELECT user_id, SUM(amount)
FROM orders
WHERE user_id = 123
AND status = 'paid'
AND created_at >= '2024-01-01'
GROUP BY user_id
ORDER BY created_at;
4. 索引维护与监控
sql
复制
下载
-- 1. 查看索引使用情况
-- 检查未使用的索引
SELECT * FROM sys.schema_unused_indexes;
-- 检查冗余索引
SELECT * FROM sys.schema_redundant_indexes;
-- 2. 索引统计信息
ANALYZE TABLE users; -- 更新统计信息
-- 查看索引统计
SHOW INDEX FROM users;
-- Cardinality: 唯一值数量(重要)
-- 选择性 = Cardinality / 总行数
-- 3. 定期维护
-- 重建索引(InnoDB)
ALTER TABLE users ENGINE=InnoDB;
-- 优化表
OPTIMIZE TABLE users;
-- 4. 监控索引大小
SELECT
table_name,
index_name,
ROUND(stat_value * @@innodb_page_size / 1024 / 1024, 2) as size_mb
FROM mysql.innodb_index_stats
WHERE stat_name = 'size'
AND database_name = DATABASE()
ORDER BY size_mb DESC;
四、SQL语句优化
1. 查询重写优化
sql
复制
下载
-- 1. 避免SELECT *
-- 错误:读取所有列
SELECT * FROM users WHERE id = 1;
-- 正确:只取需要的列
SELECT id, name, email FROM users WHERE id = 1;
-- 2. 使用EXISTS代替IN(大数据集)
-- IN需要执行子查询并缓存结果
SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders WHERE amount > 1000);
-- EXISTS更高效
SELECT * FROM users u
WHERE EXISTS (
SELECT 1 FROM orders o
WHERE o.user_id = u.id AND o.amount > 1000
);
-- 3. 使用JOIN代替子查询
-- 子查询可能执行多次
SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders);
-- JOIN通常更高效
SELECT DISTINCT u.*
FROM users u
JOIN orders o ON u.id = o.user_id;
-- 4. 拆分复杂查询
-- 复杂的单条查询
SELECT * FROM orders
WHERE (status = 'pending' AND created_at > '2024-01-01')
OR (user_id IN (SELECT id FROM users WHERE vip = 1));
-- 拆分为多条
SELECT * FROM orders
WHERE status = 'pending' AND created_at > '2024-01-01'
UNION
SELECT o.* FROM orders o
JOIN users u ON o.user_id = u.id
WHERE u.vip = 1;
2. JOIN优化策略
sql
复制
下载
-- 1. 小表驱动大表
-- 假设:users表小,orders表大
-- 好的JOIN顺序
SELECT * FROM users u
JOIN orders o ON u.id = o.user_id;
-- 2. 确保JOIN字段有索引
-- users.id和orders.user_id都应该有索引
CREATE INDEX idx_orders_user ON orders(user_id);
-- 3. 避免多表JOIN
-- 超过3个表的JOIN可能导致性能问题
-- 考虑:拆分查询、冗余字段、应用层JOIN
-- 4. 使用STRAIGHT_JOIN强制连接顺序
-- 当优化器选择错误时使用
SELECT STRAIGHT_JOIN u.*, o.*
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.status = 'active';
-- 5. JOIN算法选择
-- MySQL支持三种JOIN算法:
-- Nested Loop Join: 默认,小表驱动
-- Hash Join: MySQL 8.0+,等值JOIN
-- Sort Merge Join: 非等值JOIN
-- 查看使用的算法
EXPLAIN FORMAT=JSON
SELECT * FROM t1 JOIN t2 ON t1.id = t2.id;
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc
需要全套面试笔记及答案
【点击此处即可/免费获取】
3. 分页查询优化
sql
复制
下载
-- 1. 传统分页的问题(偏移量大时慢)
SELECT * FROM orders
ORDER BY created_at DESC
LIMIT 1000000, 20; -- 扫描1000020行,返回20行
-- 2. 使用覆盖索引+子查询优化
SELECT * FROM orders o
JOIN (
SELECT id FROM orders
ORDER BY created_at DESC
LIMIT 1000000, 20
) AS tmp ON o.id = tmp.id;
-- 3. 使用游标分页(基于ID)
-- 第一页
SELECT * FROM orders
ORDER BY id
LIMIT 20;
-- 第二页(记住上一页最后一条的id)
SELECT * FROM orders
WHERE id > 上一页最后一条id
ORDER BY id
LIMIT 20;
-- 4. 使用时间范围分页
SELECT * FROM orders
WHERE created_at < '上一页最后时间'
ORDER BY created_at DESC
LIMIT 20;
-- 5. 使用延迟关联
SELECT * FROM orders o
INNER JOIN (
SELECT id FROM orders
WHERE status = 'paid'
ORDER BY created_at DESC
LIMIT 1000000, 20
) AS tmp ON o.id = tmp.id;
4. 聚合查询优化
sql
复制
下载
-- 1. 避免在WHERE中使用聚合函数
-- 错误:全表扫描
SELECT * FROM orders
WHERE amount > (SELECT AVG(amount) FROM orders);
-- 正确:先计算再关联
WITH avg_amount AS (
SELECT AVG(amount) as avg_amt FROM orders
)
SELECT o.* FROM orders o, avg_amount a
WHERE o.amount > a.avg_amt;
-- 2. 使用窗口函数代替自连接
-- 查询每个用户的订单数排名
-- 传统方式
SELECT u1.id, u1.name, COUNT(o.id) as order_count,
(SELECT COUNT(DISTINCT u2.id)
FROM users u2
JOIN orders o2 ON u2.id = o2.user_id
WHERE COUNT(o2.id) > COUNT(o.id)) + 1 as rank
FROM users u1
JOIN orders o ON u1.id = o.user_id
GROUP BY u1.id;
-- 窗口函数更高效
SELECT id, name, order_count,
DENSE_RANK() OVER (ORDER BY order_count DESC) as rank
FROM (
SELECT u.id, u.name, COUNT(o.id) as order_count
FROM users u
JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name
) t;
-- 3. 预聚合数据
-- 创建汇总表
CREATE TABLE user_order_summary (
user_id INT PRIMARY KEY,
order_count INT,
total_amount DECIMAL(10,2),
last_order_date DATETIME,
INDEX idx_total_amount (total_amount)
);
-- 定期更新汇总表
INSERT INTO user_order_summary
SELECT
user_id,
COUNT(*) as order_count,
SUM(amount) as total_amount,
MAX(created_at) as last_order_date
FROM orders
GROUP BY user_id
ON DUPLICATE KEY UPDATE
order_count = VALUES(order_count),
total_amount = VALUES(total_amount),
last_order_date = VALUES(last_order_date);
五、数据库设计优化
1. 表结构设计优化
sql
复制
下载
-- 1. 选择合适的数据类型
-- 避免使用大字段类型
-- 错误
CREATE TABLE logs (
id BIGINT,
content TEXT, -- 可能过大
created_at DATETIME
);
-- 正确
CREATE TABLE logs (
id INT UNSIGNED, -- 根据数据量选择
content VARCHAR(1000), -- 限制长度
created_at TIMESTAMP -- 更小的存储空间
);
-- 2. 合理使用NULL
-- NULL需要额外存储空间,且索引更复杂
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
phone VARCHAR(20) NULL, -- 允许NULL
INDEX idx_phone (phone)
);
-- 3. 垂直拆分大表
-- 原始大表
CREATE TABLE user_profile (
id INT PRIMARY KEY,
basic_info JSON, -- 频繁访问
extended_info JSON, -- 不常访问
audit_log JSON, -- 很少访问
created_at TIMESTAMP
);
-- 垂直拆分
CREATE TABLE user_basic (
id INT PRIMARY KEY,
basic_info JSON,
created_at TIMESTAMP
);
CREATE TABLE user_extended (
user_id INT PRIMARY KEY,
extended_info JSON,
FOREIGN KEY (user_id) REFERENCES user_basic(id)
);
-- 4. 水平分表策略
-- 按时间分表
CREATE TABLE orders_2024 (
LIKE orders INCLUDING ALL,
CHECK (created_at >= '2024-01-01' AND created_at < '2025-01-01')
);
-- 按哈希分表
CREATE TABLE orders_00 (
LIKE orders INCLUDING ALL,
CHECK (user_id % 10 = 0)
);
-- ...创建orders_01到orders_09
2. 范式与反范式设计
sql
复制
下载
-- 1. 第三范式(3NF)示例
-- 完全规范化
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100),
country_id INT,
FOREIGN KEY (country_id) REFERENCES countries(id)
);
CREATE TABLE countries (
id INT PRIMARY KEY,
name VARCHAR(100),
continent_id INT,
FOREIGN KEY (continent_id) REFERENCES continents(id)
);
-- 查询需要多次JOIN
SELECT u.name, c.name as country, ct.name as continent
FROM users u
JOIN countries c ON u.country_id = c.id
JOIN continents ct ON c.continent_id = ct.id;
-- 2. 适度反范式(冗余字段)
CREATE TABLE users_denormalized (
id INT PRIMARY KEY,
name VARCHAR(100),
country_name VARCHAR(100), -- 冗余字段
continent_name VARCHAR(100) -- 冗余字段
);
-- 查询更简单
SELECT name, country_name, continent_name
FROM users_denormalized;
-- 3. 物化视图(MySQL不支持,但可手动实现)
CREATE TABLE user_order_stats (
user_id INT PRIMARY KEY,
order_count INT,
total_amount DECIMAL(10,2),
avg_amount DECIMAL(10,2),
last_order_date DATETIME,
INDEX idx_total_amount (total_amount)
);
-- 定期刷新
REPLACE INTO user_order_stats
SELECT
user_id,
COUNT(*) as order_count,
SUM(amount) as total_amount,
AVG(amount) as avg_amount,
MAX(created_at) as last_order_date
FROM orders
GROUP BY user_id;
3. 分区表优化
sql
复制
下载
-- 1. 范围分区(按时间)
CREATE TABLE orders_partitioned (
id INT AUTO_INCREMENT,
user_id INT,
amount DECIMAL(10,2),
created_at DATETIME,
PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (YEAR(created_at)) (
PARTITION p2020 VALUES LESS THAN (2021),
PARTITION p2021 VALUES LESS THAN (2022),
PARTITION p2022 VALUES LESS THAN (2023),
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p_max VALUES LESS THAN MAXVALUE
);
-- 2. 哈希分区(均匀分布)
CREATE TABLE users_partitioned (
id INT AUTO_INCREMENT,
name VARCHAR(100),
email VARCHAR(100),
PRIMARY KEY (id)
) PARTITION BY HASH(id)
PARTITIONS 10;
-- 3. 列表分区(按地区)
CREATE TABLE sales_partitioned (
id INT AUTO_INCREMENT,
region VARCHAR(20),
amount DECIMAL(10,2),
sale_date DATE,
PRIMARY KEY (id, region)
) PARTITION BY LIST COLUMNS(region) (
PARTITION p_east VALUES IN ('NY', 'NJ', 'CT'),
PARTITION p_west VALUES IN ('CA', 'OR', 'WA'),
PARTITION p_south VALUES IN ('TX', 'FL', 'GA'),
PARTITION p_other VALUES IN (DEFAULT)
);
-- 4. 分区维护
-- 添加分区
ALTER TABLE orders_partitioned
ADD PARTITION (PARTITION p2025 VALUES LESS THAN (2026));
-- 删除分区(数据也会删除)
ALTER TABLE orders_partitioned
DROP PARTITION p2020;
-- 重建分区
ALTER TABLE orders_partitioned
REBUILD PARTITION p2024;
-- 5. 分区查询优化
-- 分区裁剪:只扫描相关分区
EXPLAIN SELECT * FROM orders_partitioned
WHERE created_at >= '2024-01-01';
六、系统级优化
1. MySQL参数调优
sql
复制
下载
-- 1. 内存相关配置
-- InnoDB缓冲池(重要!)
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
-- 建议:物理内存的70-80%
-- 查询缓存(MySQL 8.0已移除)
-- 排序缓冲区
SHOW VARIABLES LIKE 'sort_buffer_size';
-- 建议:2-8MB
-- 连接缓冲区
SHOW VARIABLES LIKE 'join_buffer_size';
-- 建议:256K-1MB
-- 2. 连接相关配置
-- 最大连接数
SHOW VARIABLES LIKE 'max_connections';
-- 建议:根据应用需求设置
-- 连接超时
SHOW VARIABLES LIKE 'wait_timeout';
-- 建议:300秒(5分钟)
-- 3. InnoDB相关配置
-- 日志文件大小
SHOW VARIABLES LIKE 'innodb_log_file_size';
-- 建议:1-4GB
-- 刷新日志频率
SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';
-- 1: 最安全(每次提交都刷新)
-- 2: 折中(每秒刷新)
-- 0: 性能最好(依赖OS刷新)
-- 4. 监控参数调整
-- 慢查询日志
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
-- 性能schema
UPDATE performance_schema.setup_consumers
SET ENABLED = 'YES'
WHERE NAME LIKE '%events_statements%';
2. 硬件与OS优化
bash
复制
下载
# 1. 磁盘优化
# 使用SSD代替HDD
# 使用RAID 10获得最佳性能
# 2. 文件系统优化
# 使用XFS或ext4
# 挂载参数:noatime,nodiratime
# 3. 内存优化
# 配置足够的Swap空间(物理内存的1-2倍)
# 使用大页(HugePages)
echo 100 > /proc/sys/vm/nr_hugepages
# 4. 网络优化
# 调整TCP参数
echo 65535 > /proc/sys/net/core/somaxconn
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
# 5. 进程限制
ulimit -n 65535 # 文件描述符数量
3. 架构层优化
sql
复制
下载
-- 1. 读写分离
-- 主库:写操作
-- 从库:读操作
-- 配置主从复制
-- 主库
SHOW MASTER STATUS;
-- 从库
CHANGE MASTER TO
MASTER_HOST='master_host',
MASTER_USER='repl',
MASTER_PASSWORD='password',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=107;
-- 2. 分库分表
-- 使用中间件:ShardingSphere、MyCat
-- 或应用层分片
-- 3. 缓存层
-- 使用Redis缓存热点数据
-- 查询缓存策略
SELECT
CASE
WHEN EXISTS(SELECT 1 FROM cache WHERE key = 'user:123')
THEN 'FROM_CACHE'
ELSE 'FROM_DB'
END as source,
data
FROM dual;
-- 4. 异步处理
-- 非实时任务使用消息队列
INSERT INTO message_queue(table_name, operation, data)
VALUES ('orders', 'INSERT', '{"id": 123, ...}');
-- 后台任务处理
CREATE EVENT process_messages
ON SCHEDULE EVERY 1 MINUTE
DO
CALL process_pending_messages();
七、高级优化技巧
1. 执行计划绑定
sql
复制
下载
-- 1. 查询重写提示
-- 强制使用某个索引
SELECT /*+ INDEX(orders idx_status) */ *
FROM orders
WHERE status = 'pending';
-- 忽略某个索引
SELECT /*+ IGNORE INDEX(orders idx_user) */ *
FROM orders
WHERE user_id = 123;
-- 强制连接顺序
SELECT /*+ STRAIGHT_JOIN */ u.*, o.*
FROM users u
JOIN orders o ON u.id = o.user_id;
-- 2. 使用优化器提示(MySQL 8.0+)
-- 设置优化器开关
SET @@optimizer_switch = 'index_merge=off';
-- 查询级设置
SELECT /*+ SET_VAR(optimizer_switch='index_merge=off') */ *
FROM orders;
-- 3. 执行计划绑定(MySQL 8.0+)
-- 创建执行计划绑定
CREATE OPTIMIZER_HINT
'SELECT * FROM orders WHERE user_id = ?'
USING
'SELECT /*+ INDEX(orders idx_user) */ *
FROM orders WHERE user_id = ?';
-- 查看绑定
SELECT * FROM performance_schema.optimizer_hints;
2. 统计信息管理
sql
复制
下载
-- 1. 自动统计信息
SHOW VARIABLES LIKE 'innodb_stats%';
-- 采样页数
SET GLOBAL innodb_stats_persistent_sample_pages = 100;
-- 自动更新
SET GLOBAL innodb_stats_auto_recalc = ON;
-- 2. 手动收集统计信息
-- 表级别
ANALYZE TABLE users;
-- 索引级别
ANALYZE TABLE users UPDATE HISTOGRAM ON age, name;
-- 3. 直方图统计(MySQL 8.0+)
-- 创建直方图
ANALYZE TABLE users
UPDATE HISTOGRAM ON age WITH 100 BUCKETS;
-- 查看直方图
SELECT * FROM information_schema.COLUMN_STATISTICS
WHERE TABLE_NAME = 'users';
-- 4. 持久化统计信息
SET GLOBAL innodb_stats_persistent = ON;
SET GLOBAL innodb_stats_persistent_sample_pages = 100;
3. 查询重写与优化器扩展
sql
复制
下载
-- 1. 使用Common Table Expressions (CTE)
-- 提高复杂查询可读性和性能
WITH user_orders AS (
SELECT user_id, COUNT(*) as order_count
FROM orders
WHERE created_at >= '2024-01-01'
GROUP BY user_id
HAVING order_count > 10
),
user_details AS (
SELECT u.id, u.name, uo.order_count
FROM users u
JOIN user_orders uo ON u.id = uo.user_id
)
SELECT * FROM user_details
ORDER BY order_count DESC;
-- 2. 窗口函数优化
-- 代替复杂子查询
SELECT
user_id,
order_id,
amount,
SUM(amount) OVER (PARTITION BY user_id) as user_total,
AVG(amount) OVER (PARTITION BY user_id) as user_avg,
RANK() OVER (PARTITION BY user_id ORDER BY amount DESC) as rank_in_user
FROM orders;
-- 3. 使用Generated Columns
-- 创建计算列并索引
ALTER TABLE orders
ADD COLUMN amount_tax DECIMAL(10,2)
GENERATED ALWAYS AS (amount * 1.1) STORED,
ADD INDEX idx_amount_tax (amount_tax);
-- 查询可以使用索引
SELECT * FROM orders WHERE amount_tax > 1000;
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc
需要全套面试笔记及答案
【点击此处即可/免费获取】
八、监控与持续优化
1. 监控指标体系
sql
复制
下载
-- 1. 性能监控
-- QPS/TPS
SHOW GLOBAL STATUS LIKE 'Questions';
SHOW GLOBAL STATUS LIKE 'Com_commit';
SHOW GLOBAL STATUS LIKE 'Com_rollback';
-- 连接数
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Threads_running';
-- 缓冲池命中率
SELECT
(1 - (Variable_value / (SELECT Variable_value
FROM information_schema.global_status
WHERE Variable_name = 'Innodb_buffer_pool_read_requests'))) * 100
as hit_rate
FROM information_schema.global_status
WHERE Variable_name = 'Innodb_buffer_pool_reads';
-- 2. 资源监控
-- 内存使用
SHOW ENGINE INNODB STATUS\G
-- 查看BUFFER POOL AND MEMORY部分
-- 磁盘IO
SHOW GLOBAL STATUS LIKE 'Innodb_data_reads';
SHOW GLOBAL STATUS LIKE 'Innodb_data_writes';
-- 3. 慢查询监控
-- 查看慢查询统计
SELECT
db,
COUNT(*) as total,
AVG(query_time) as avg_time,
MAX(query_time) as max_time,
SUM(rows_sent) as total_rows_sent,
SUM(rows_examined) as total_rows_examined
FROM mysql.slow_log
WHERE start_time > NOW() - INTERVAL 1 DAY
GROUP BY db;
2. 自动化优化工具
bash
复制
下载
# 1. Percona Toolkit
# 分析慢查询
pt-query-digest slow.log
# 优化表
pt-online-schema-change --alter "ADD INDEX idx_email(email)" D=mydb,t=users
# 2. MySQLTuner
# 自动分析配置
wget https://raw.githubusercontent.com/major/MySQLTuner-perl/master/mysqltuner.pl
perl mysqltuner.pl
# 3. 压力测试工具
# sysbench
sysbench oltp_read_write --table-size=1000000 prepare
sysbench oltp_read_write --table-size=1000000 --threads=8 --time=300 run
# 4. 监控平台
# Prometheus + Grafana
# 或使用云服务:AWS RDS Performance Insights
3. 优化工作流程
sql
复制
下载
-- 1. 问题发现
-- 监控报警 -> 慢查询日志 -> 用户反馈
-- 2. 问题分析
-- 使用EXPLAIN分析执行计划
-- 使用SHOW PROFILE查看执行细节
SET profiling = 1;
SELECT * FROM orders WHERE user_id = 123;
SHOW PROFILES;
SHOW PROFILE FOR QUERY 1;
-- 3. 优化实施
-- 索引优化 -> 查询重写 -> 配置调整 -> 架构调整
-- 4. 效果验证
-- A/B测试
-- 监控对比
-- 5. 文档记录
-- 创建优化知识库
CREATE TABLE optimization_log (
id INT AUTO_INCREMENT PRIMARY KEY,
problem_description TEXT,
sql_text TEXT,
original_plan JSON,
optimized_plan JSON,
optimization_action TEXT,
performance_improvement DECIMAL(5,2),
optimized_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
九、实战案例
案例1:电商订单查询优化
sql
复制
下载
-- 原始查询(执行时间:8.5秒)
SELECT * FROM orders
WHERE user_id = 123
AND status IN ('pending', 'processing')
AND created_at >= '2024-01-01'
ORDER BY created_at DESC
LIMIT 20;
-- 优化步骤:
-- 1. 分析执行计划
EXPLAIN SELECT * FROM orders WHERE ...;
-- 发现:全表扫描,filesort
-- 2. 创建合适索引
CREATE INDEX idx_user_status_time ON orders(user_id, status, created_at);
-- 3. 优化查询语句
-- 使用覆盖索引
SELECT id, user_id, status, amount, created_at
FROM orders
WHERE user_id = 123
AND status IN ('pending', 'processing')
AND created_at >= '2024-01-01'
ORDER BY created_at DESC
LIMIT 20;
-- 4. 进一步优化(数据量大时)
-- 使用延迟关联
SELECT o.* FROM orders o
JOIN (
SELECT id FROM orders
WHERE user_id = 123
AND status IN ('pending', 'processing')
AND created_at >= '2024-01-01'
ORDER BY created_at DESC
LIMIT 20
) AS tmp ON o.id = tmp.id;
-- 优化后执行时间:0.02秒
案例2:报表查询优化
sql
复制
下载
-- 原始查询(执行时间:25秒)
SELECT
DATE(created_at) as day,
COUNT(*) as order_count,
SUM(amount) as total_amount,
AVG(amount) as avg_amount
FROM orders
WHERE created_at >= '2024-01-01'
AND status = 'completed'
GROUP BY DATE(created_at)
ORDER BY day DESC;
-- 优化方案:
-- 1. 创建汇总表
CREATE TABLE daily_order_stats (
date DATE PRIMARY KEY,
order_count INT DEFAULT 0,
total_amount DECIMAL(15,2) DEFAULT 0,
avg_amount DECIMAL(10,2) DEFAULT 0,
last_updated TIMESTAMP
);
-- 2. 增量更新汇总表
CREATE EVENT update_daily_stats
ON SCHEDULE EVERY 1 HOUR
DO
BEGIN
DECLARE last_update TIMESTAMP;
SELECT MAX(last_updated) INTO last_update
FROM daily_order_stats;
IF last_update IS NULL THEN
SET last_update = '2024-01-01';
END IF;
INSERT INTO daily_order_stats (date, order_count, total_amount, avg_amount, last_updated)
SELECT
DATE(created_at) as date,
COUNT(*) as order_count,
SUM(amount) as total_amount,
AVG(amount) as avg_amount,
NOW() as last_updated
FROM orders
WHERE created_at > last_update
AND status = 'completed'
GROUP BY DATE(created_at)
ON DUPLICATE KEY UPDATE
order_count = order_count + VALUES(order_count),
total_amount = total_amount + VALUES(total_amount),
avg_amount = (total_amount + VALUES(total_amount)) /
(order_count + VALUES(order_count)),
last_updated = NOW();
END;
-- 3. 查询优化后
SELECT * FROM daily_order_stats
WHERE date >= '2024-01-01'
ORDER BY date DESC;
-- 执行时间:0.01秒
十、总结与最佳实践
📋 优化检查清单:
-
✅ 是否开启慢查询日志?
-
✅ 是否分析EXPLAIN执行计划?
-
✅ 索引设计是否合理?
-
最左前缀原则
-
覆盖索引
-
避免索引失效
-
-
✅ SQL语句是否最优?
-
避免SELECT *
-
优化JOIN顺序
-
合理使用子查询
-
-
✅ 分页查询是否优化?
-
✅ 数据库配置是否调优?
-
✅ 表结构设计是否合理?
-
✅ 是否有监控报警?
🎯 优化优先级:
-
紧急优化(影响核心功能)
-
全表扫描查询
-
死锁频繁发生
-
连接数打满
-
-
重要优化(影响用户体验)
-
响应时间>2秒的查询
-
高频查询未用索引
-
内存使用率过高
-
-
常规优化(提升系统性能)
-
索引维护
-
统计信息更新
-
配置调优
-
📊 性能指标目标:
| 指标 | 优秀 | 良好 | 需要优化 |
|---|---|---|---|
| 查询响应时间 | <100ms | <500ms | >1s |
| QPS | >1000 | >500 | <100 |
| 连接数使用率 | <50% | <80% | >90% |
| 缓冲池命中率 | >99% | >95% | <90% |
| 慢查询比例 | <1% | <5% | >10% |
记住:优化是一个持续的过程,不是一次性的任务。建立完善的监控体系,定期进行性能评估,才能保证数据库长期稳定高效运行。