当数据库响应时间超过500ms时,系统将面临三大灾难链式反应:
通过监控系统捕获的真实案例:某电商平台在促销期间因未优化的GROUP BY
语句导致每秒丢失23个订单,直接经济损失每小时超50万元。
-- 动态开启记录(重启失效)
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1; -- 单位:秒
SET GLOBAL log_queries_not_using_indexes = 'ON';
-- 永久生效配置(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
EXPLAIN执行计划解读:
EXPLAIN SELECT o.order_id, c.name
FROM orders o
JOIN customers c ON o.cust_id = c.id
WHERE o.status = 'PAID'
AND o.create_time > '2023-01-01';
-- 关键指标解读
/*
+----+-------------+-------+------+---------------+---------+---------+-------------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+---------+---------+-------------------+--------+-------------+
| 1 | SIMPLE | o | ref | idx_status | idx_status | 82 | const | 156892 | Using where |
| 1 | SIMPLE | c | eq_ref| PRIMARY | PRIMARY | 4 | db.o.cust_id | 1 | NULL |
+----+-------------+-------+------+---------------+---------+---------+-------------------+--------+-------------+
*/
SHOW PROFILE深度分析:
SET profiling = 1;
-- 执行目标SQL
SELECT /*+ 测试SQL */ ...;
SHOW PROFILES;
SHOW PROFILE CPU, BLOCK IO FOR QUERY 7;
/* 典型问题输出
+----------------------+----------+----------+------------+
| Status | Duration | CPU_user | Block_ops |
+----------------------+----------+----------+------------+
| starting | 0.000065 | 0.000000 | 0 |
| checking permissions | 0.000007 | 0.000000 | 0 |
| Opening tables | 0.000023 | 0.000000 | 0 |
| Sorting result | 2.134567 | 1.982342 | 1245 | <-- 排序耗时严重
| Sending data | 0.000045 | 0.000000 | 0 |
+----------------------+----------+----------+------------+
*/
Performance Schema监控:
-- 查看最耗资源的SQL
SELECT sql_text,
SUM_TIMER_WAIT/1e12 AS total_sec,
SUM_ROWS_EXAMINED
FROM performance_schema.events_statements_summary_by_digest
WHERE digest_text LIKE 'SELECT%'
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 5;
创建原则:
WHERE > ORDER BY > GROUP BY
顺序INDEX (name(20))
索引失效的7种场景:
-- 1. 隐式类型转换
SELECT * FROM users WHERE phone = 13800138000; -- phone是varchar类型
-- 2. 索引列参与运算
SELECT * FROM logs WHERE YEAR(create_time) = 2023;
-- 3. 前导通配符查询
SELECT * FROM products WHERE name LIKE '%Pro%';
-- 4. OR条件混合使用
SELECT * FROM orders WHERE status = 'PAID' OR amount > 1000;
-- 5. 违反最左前缀原则
INDEX idx_a_b_c (a,b,c)
WHERE b=1 AND c=2 -- 无法使用索引
-- 6. 使用否定条件
SELECT * FROM users WHERE status != 'ACTIVE';
-- 7. 索引列使用函数
SELECT * FROM orders WHERE UPPER(order_no) = 'ABC123';
分页查询优化:
-- 原始写法(扫描100100行)
SELECT * FROM orders
ORDER BY id
LIMIT 100000, 100;
-- 优化写法(扫描100行)
SELECT * FROM orders
WHERE id > 100000
ORDER BY id
LIMIT 100;
连接查询优化:
-- 低效嵌套查询
SELECT * FROM users
WHERE id IN (
SELECT user_id FROM orders
WHERE amount > 1000
);
-- 优化为JOIN
SELECT u.*
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE o.amount > 1000;
强制索引使用:
SELECT * FROM orders
FORCE INDEX(idx_status_create_time)
WHERE status = 'SHIPPED'
AND create_time > '2023-06-01';
优化器提示:
SELECT /*+ MAX_EXECUTION_TIME(1000) */ ...
FROM large_table
WHERE ...;
SELECT /*+ MRR(buf_size=16M) */ ...
FROM sales
WHERE sale_date BETWEEN ...;
# InnoDB配置优化
innodb_buffer_pool_size = 物理内存的70-80%
innodb_flush_log_at_trx_commit = 2 # 非关键业务
innodb_io_capacity = 2000 # SSD配置
# 查询缓存优化
query_cache_type = 0 # 8.0+版本已移除
读写分离架构:
应用层 -> 中间件 -> 主库(写)
-> 从库1(读)
-> 从库2(读)
分库分表策略:
orders_2023q1
user_basic
与user_extra
分离原始SQL:
SELECT COUNT(*)
FROM user_behavior
WHERE create_time BETWEEN '2023-01-01' AND '2023-06-30';
-- 执行时间:12.8秒
-- 优化步骤:
1. 创建函数索引:ALTER TABLE ADD INDEX idx_ymd ((DATE_FORMAT(create_time,'%Y%m%d')))
2. 分批统计后汇总:
SELECT SUM(cnt) FROM (
SELECT COUNT(*) cnt FROM user_behavior_202301
UNION ALL
SELECT COUNT(*) FROM user_behavior_202302
...
) tmp;
-- 优化后时间:0.9秒
原始语句:
SELECT product_id,
AVG(rating),
COUNT(DISTINCT user_id)
FROM reviews
GROUP BY product_id
HAVING COUNT(*) > 100;
-- 执行时间:7.2秒
-- 优化方案:
1. 创建汇总表:
CREATE TABLE product_stats (
product_id INT PRIMARY KEY,
total_reviews INT,
avg_rating DECIMAL(3,2),
unique_users INT
);
2. 使用触发器实时更新
-- 查询时间降至0.03秒
-- 字段类型为VARCHAR(32)
SELECT * FROM devices WHERE imei = 123456789012345; -- 全表扫描
SELECT * FROM devices WHERE imei = '123456789012345'; -- 走索引
-- 错误的长事务
BEGIN;
SELECT * FROM products; -- 耗时查询
UPDATE inventory SET ...;
COMMIT;
-- 优化为:
START TRANSACTION READ ONLY;
SELECT * FROM products;
COMMIT;
BEGIN;
UPDATE inventory SET ...;
COMMIT;
通过系统的优化实践,某金融系统成功将平均查询耗时从870ms降至68ms,TPS从1200提升到9500。记住:SQL优化不是一次性工作,而是需要持续监控、迭代改进的过程。当遇到性能瓶颈时,请遵循定位→分析→验证→实施
的黄金闭环,让您的数据库始终保持在最佳状态!