| name | sql-optimization |
| description | SQL 优化与调优 |
| version | 1.0.0 |
| author | terminal-skills |
| tags | ["database","sql","optimization","performance","index"] |
SQL 优化与调优
概述
慢查询分析、执行计划、索引优化等通用 SQL 优化技能。
执行计划分析
MySQL EXPLAIN
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';
EXPLAIN FORMAT=JSON SELECT * FROM users WHERE email = 'test@example.com';
PostgreSQL EXPLAIN
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT) SELECT * FROM users WHERE email = 'test@example.com';
索引优化
索引设计原则
SELECT COUNT(DISTINCT column) / COUNT(*) AS selectivity FROM table;
CREATE INDEX idx_user ON users(status, created_at, name);
CREATE INDEX idx_covering ON orders(user_id, status, amount);
SELECT user_id, status, amount FROM orders WHERE user_id = 1;
CREATE INDEX idx_email ON users(email(20));
索引使用检查
SELECT * FROM sys.schema_index_statistics WHERE table_schema = 'mydb';
SELECT * FROM sys.schema_unused_indexes WHERE object_schema = 'mydb';
SELECT indexrelname, idx_scan, idx_tup_read, idx_tup_fetch
FROM pg_stat_user_indexes
WHERE schemaname = 'public'
ORDER BY idx_scan;
索引失效场景
SELECT * FROM users WHERE YEAR(created_at) = 2024;
SELECT * FROM users WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01';
SELECT * FROM users WHERE phone = 13800138000;
SELECT * FROM users WHERE phone = '13800138000';
SELECT * FROM users WHERE name LIKE '%john%';
SELECT * FROM users WHERE name LIKE 'john%';
SELECT * FROM users WHERE status = 1 OR name = 'john';
SELECT * FROM users WHERE status = 1
UNION
SELECT * FROM users WHERE name = 'john';
SELECT * FROM users WHERE id NOT IN (SELECT user_id FROM orders);
SELECT u.* FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE o.id IS NULL;
查询优化
SELECT 优化
SELECT * FROM users;
SELECT id, name, email FROM users;
SELECT * FROM logs ORDER BY created_at DESC LIMIT 100;
SELECT * FROM users LIMIT 10000, 20;
SELECT * FROM users WHERE id > 10000 ORDER BY id LIMIT 20;
JOIN 优化
SELECT u.name, o.amount
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.status = 1;
SELECT STRAIGHT_JOIN u.name, o.amount
FROM users u
JOIN orders o ON u.id = o.user_id;
子查询优化
SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE amount > 100);
SELECT DISTINCT u.* FROM users u JOIN orders o ON u.id = o.user_id WHERE o.amount > 100;
SELECT * FROM users u WHERE EXISTS (
SELECT 1 FROM orders o WHERE o.user_id = u.id AND o.amount > 100
);
慢查询分析
MySQL 慢查询
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';
PostgreSQL 慢查询
CREATE EXTENSION pg_stat_statements;
SELECT query, calls, total_time, mean_time, rows
FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 10;
常见场景
场景 1:大表分页
SELECT u.* FROM users u
JOIN (SELECT id FROM users ORDER BY created_at DESC LIMIT 10000, 20) t
ON u.id = t.id;
SELECT * FROM users
WHERE id > last_seen_id
ORDER BY id
LIMIT 20;
场景 2:批量更新
UPDATE users SET status = 1 WHERE id BETWEEN 1 AND 1000;
UPDATE users SET status = 1 WHERE id BETWEEN 1001 AND 2000;
场景 3:统计查询优化
CREATE TABLE daily_stats (
date DATE PRIMARY KEY,
total_orders INT,
total_amount DECIMAL(10,2)
);
INSERT INTO daily_stats
SELECT DATE(created_at), COUNT(*), SUM(amount)
FROM orders
WHERE DATE(created_at) = CURDATE() - INTERVAL 1 DAY
GROUP BY DATE(created_at)
ON DUPLICATE KEY UPDATE
total_orders = VALUES(total_orders),
total_amount = VALUES(total_amount);
场景 4:锁优化
SELECT * FROM users FOR UPDATE;
SELECT * FROM users WHERE id = 1 FOR UPDATE;
UPDATE users SET balance = balance - 100, version = version + 1
WHERE id = 1 AND version = 5;
优化检查清单
| 检查项 | 说明 |
|---|
| 执行计划 | 是否全表扫描、是否使用索引 |
| 索引设计 | 选择性、覆盖索引、复合索引顺序 |
| 查询改写 | 避免 SELECT *、优化子查询 |
| 分页方式 | 大偏移量使用游标分页 |
| 批量操作 | 分批处理、避免长事务 |
| 锁粒度 | 减少锁范围、使用乐观锁 |